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>
Date: Tue, 5 Sep 2017 11:58:42 -0500
Hi Giacomo,

On 09/05/2017 10:01 AM, Giacomo S. wrote:
> So, summing up, suppose to recreate this scenario:
> 
> - application starts
> --> client requests monitoring of  pv1 = foo:ai1
> 
> - (first request, so)   ca_context_create(ca_enable_preemptive_callback)
> 
> - ca_create_channel (...)
> 
> - (in  connection_handler invoked from EPICS foo thread: ) 
> ca_create_subscription(...)

A note: You are allowed to subscribe to channels using a different
request data type than their native type, and the IOC will do its best
to convert the data for you. I don't completely understand how your
connection_handler() method transforms the native type, but I just
wanted to make that point for later on...

> [ monitors for a while, receive event callbacks from EPICS foo thread]
> 
> --> client requests pv2  = foo:ai2
> 
>  - ca_create_channel (...)
> 
> - (in  connection_handler invoked from EPICS foo thread: ) 
> ca_create_subscription(...)
> 
> 
> ---> network goes down
> 
> - (in pv1 connection callback invoked from EPICS foo thread:)  1. 
> ca_clear_subscription()   BUT NOT ca_clear_channel()

Here's where Michael and I have slightly differing opinions: I wouldn't
necessarily clear the subscription when the connection goes down,
especially if I'm not relying on the native data type of the channel to
select what type I subscribe with. CA will remember the original
subscription and will reconnect it to the IOC when it comes back. In
connection_handler() you were already storing the fact that you have
already subscribed, so that code wouldn't create multiple subscriptions.

One issue that you do have to be careful of though is if an IOC gets
rebooted with a modified database so the data type of a channel you were
subscribed to changes between the connection going down and coming back
up. In this case CA subscriptions will reconnect using the type in their
original subscription request, which might now be different to the
native type of the channel. The client code has to be aware of that and
use the type information from the data update callback.

Michael's approach of clearing subscriptions at disconnect is probably
safer, but requires the application code to do a bit more work, as
evidenced by the additional calls to ca_create_subscription() below. The
difference is really a matter of opinion.

> - (in pv2 connection callback invoked from EPICS foo thread:)  1. 
> ca_clear_subscription()      BUT NOT   ca_clear_channel()
> 
> ---> network UP again
> 
> 
> - (in pv1 connection callback invoked from EPICS foo thread:)  1. 
> ca_create_subscription() 
> 
> - (in pv2 connection callback invoked from EPICS foo thread:)  1. 
> ca_create_subscription()  
> 
> ---> client requests pv3  = bar:ai3
> 
>  - ca_create_channel (...)
> 
> - (in  connection_handler invoked from EPICS >>> bar <<<  thread: ) 
> ca_create_subscription(...)   <--- bar THREAD <----
> 
> [ receive event callbacks from 2 threads: foo for pv1 and pv2,  bar for
> pv3 ]
> 
> ---> client wants to disconnect everything (or application shutdown)
> 
> - foreach pv:                                                 // is this
> safe to be called from the thread that initially called the ca_create* 
> counterparts???

You can call any ca routine from any thread that has been attached to
the context, so yes.

>   * ca_clear_subscription();
>   * ca_clear_channel();
> 
> - ca_context_destroy();                                // from same
> thread where ca_context_create() was called
> 
> 
> Is the above correct? Am I somewhere wrong?

It looks like you understand it pretty well.


> Some more simpler questions:
> 
> 1. every time I receive an event, evargs contain not only the value /
> timestamp but also configuration parameters, right (HI, LO thresholds
> and so on...)

Not sure what the question is there. Your event_handler_cb() routine is
given a struct event_handler_args whose void *dbr pointer points to the
dbr_* type that you subscribed to. There are many different dbr_* data
types defined in db_access.h containing different subsets of the
available data, but none of them provides everything, so you may need to
subscribe to the same channel multiple times with different types and
different event masks. Channel metadata (enum strings, alarm levels etc)
usually change much less frequently than the data itself, and the event
mask DBE_PROPERTY is designed to tell you when metadata has changed.

> 2. are there utility functions to extract the value and timestamp from
> the evargs and easily convert them into  the correct type (short,
> double, int...)

There are some macros in db_access.h that can help, e.g. dbr_value_ptr

if you limit the number of types you subscribe to you can avoid having
to write code that understands all the dbr_* types.

> 3. If I monitor a PV, is it possible to know from the args if it's a
> vector (and its dimension) or a scalar?

Yes, the struct event_handler_args contains the data type, chid and
element count for the data contained in this update (look in cadef.h for
its definition). count==1 means it's a scalar.

> 4. where can I find the explanation of this: Lo disp limit, hi disp
> limit, Lo alarm limit.... ?

Those metadata fields are supplied from fields of the record, disp =
display, so a graph of the channel data over time should expect to use
the low display limit for the bottom of the y axis and the high display
limit for the top. Alarm limits tell you if the PV generates alarms what
data values would trigger those alarms, so you could put a marker on the
axis if you chose to do so.

> 5. How to extract the timestamp of the event (as far as I've seen from
> the code, there must be a timestamp from the server and one from the
> client. In this case, what does the client side timestamp mean. Is it
> the timestamp when the event is received on the client itself?)

You appear to be looking at code from catools, which added the idea of
providing a client-side timestamp as well as or instead of the timestamp
from the IOC itself. I think it just provides the client's idea of the
time when the CA library called its callback; this isn't part of the CA
client library itself.

> Is there a good tutorial for a quick start and the answers to my
> questions 1 to 5?
> I mean a quick start to understand how to program a client in C (C++).

Maybe not at the level of detail you're asking, I think you've probably
gone beyond what most CA client tutorials covered, but you could browse
the EPICS Training links to see if there are any that help:
    http://www.aps.anl.gov/epics/docs/training.php

> One final thing: I've seen a set of C++ libraries (pvaClientCPP,
> pvCommonCPP)  and in general the
> 
> "EPICS V4 C++ module"
> 
> but it looks like it's not up to date with the latest EPICS release.
> 
> Is this the "official" C++ Epics module?
> 
> Is it normal that it trails the last EPICS version?

Those modules are part of the newer EPICS V4 network protocol
implementation, which are designed to supplement and eventually replace
the CA protocol. That's a completely different topic and the APIs are
completely different, I suggest you ignore them for now.

HTH,

- 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.
Re: C++ multi threaded application. Giacomo S.
References:
C++ multi threaded application. Giacomo S.
Re: C++ multi threaded application. Andrew Johnson
Re: C++ multi threaded application. Giacomo S.
Re: C++ multi threaded application. Giacomo S.

Navigate by Date:
Prev: Re: C++ multi threaded application. Giacomo S.
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: Re: 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, 07 Sep 2017 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·