Argonne National Laboratory

Experimental Physics and
Industrial Control System

1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  <2017 Index 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  <2017
<== Date ==> <== Thread ==>

Subject: Re: C++ multi threaded application.
From: Andrew Johnson <anj@aps.anl.gov>
To: Giacomo S. <giacomo.strangolino@elettra.eu>, <tech-talk@aps.anl.gov>
Cc: Lucio Zambon <lucio.zambon@elettra.trieste.it>
Date: Fri, 1 Sep 2017 11:31:54 -0500
Hi Giacomo,

Welcome to the EPICS community!

On 09/01/2017 09:59 AM, Giacomo S. wrote:
> I am new to Epics, and I am writing a C++ multi threaded library in
> order to write GUIs in Qt and I have the following constraints:

Are you aware that there are already a number of EPICS projects using
Qt? You might want to take a look at them since they have already
debugged the kinds of issues you may be faced with. The main one you
should start with is epicsQt, https://github.com/qtepics or
https://qtepics.github.io/index.html

> - I want to monitor a pv in a separate thread;
> 
> - when a new value is available, I want a callback to be invoked (always
> in the same background thread). There I extract data and forward it to
> the main (GUI) thread.
> 
> - the background thread implements a wait condition so that it sleeps
> until a new event arrives (for example, exit event or new variable to be
> monitored is added)

You should be aware that the Channel Access client library creates a
background thread for each separate IOC it connects to, and it calls
your callback routines from those threads. You have no control over
that, if you talk to PVs on 2 IOCs you will get callbacks from 2
threads. The only difference that enabling preemptive callbacks has on
that is to allow callbacks to be run as soon as they are ready to be
run. For thread-sensitive systems like Qt you need to plan for that.

> I set things up like this in the init() method of a class I called
> "CuMonitorActivity".
> 
> I used a pv structure as in camonitor C example:
> 
> 
> void CuMonitorActivity::init()
> {
<snip>
> }
> 
> NOTE: I enabled preemptive_callback so that I get
> connection_handler_cb() called regularly when a new event arrives

You didn't show the routine that actually creates the channel and passes
in the connection_handler_cb() routine, but a CA *connection handler* is
only called when the connection state changes, i.e. when the program
first connects to the PV, and then again later if/when the IOC gets
started or stopped (or the network is unplugged, etc); that callback
doesn't see any data from the PV. If you want to see value changes from
the PV you have to create a subscription to the channel, and give that a
different callback routine.

> From within connection_handler_cb I extract the current
> CuMonitorActivity instance (stored in pv's monitor_activity field) and I
> invoke the object's extraction method. Data is posted in the main thread.
> 
> NOTE: I notice that connection_handler_cb is invoked from ANOTHER
> thread, not my main thread, not my secondary thread. This should be as
> expected I guess for things to work and given the ca_
> enable_preemptive_callback option.

Right, see my remarks about threading above. Note that you are allowed
to make calls to other CA routines from within your callbacks, and in
fact that is the recommended way to set up your subscriptions. However
you should be careful to only subscribe for data from a PV only once; if
the IOC gets restarted your connection handler will be called again on
reconnect, and unless you're careful that code might create a second
subscription to the same PV, which will result in your event callback
being run twice or more for each data update from the IOC.

> * when I post an "exitEvent" on my secondary thread from the main one
> (e.g. the GUI is closed),  "ca_context_destroy();" is invoked in my
> secondary thread (not the Epics thread that calls connection_handler_cb
> during monitoring - is this OK? )

Yes, as long as the thread was attached to the CA context. You should
attach all threads that you want to make CA calls from to your original
context using ca_current_context() and ca_attach_context().

> * Is there a way to ADD more PVs to monitor WHILE others are being
> monitored (for example, is it legit to call create_pvs() again ) ?

Yes, although you didn't show us your create_pvs() routine. You can add
and remove channels and subscriptions whenever you like; about the only
thing you can't call from within a callback routine is ca_pend_event().

> * Are there any observations/corrections to my approach and to my
> statements above?

Go check out epicsQt before you spend more time reinventing the wheel.
There is a separate mailing list for EPICS users programming with Qt and
you might want to subscribe to that:
    http://www.aps.anl.gov/epics/qti-talk/index.php

- Andrew

-- 
Arguing for surveillance because you have nothing to hide is no
different than making the claim, "I don't care about freedom of
speech because I have nothing to say." -- Edward Snowdon

Replies:
Re: C++ multi threaded application. Giacomo S.
References:
C++ multi threaded application. Giacomo S.

Navigate by Date:
Prev: Re: FTP server on Linux(Ubuntu) Andrew Johnson
Next: Re: Archiver: Problems with disconnected PVs Shankar, Murali
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  <2017
Navigate by Thread:
Prev: C++ multi threaded application. Giacomo S.
Next: Re: C++ multi threaded application. Giacomo S.
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  <2017
ANJ, 04 Sep 2017 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·