EPICS Controls 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  <20162017  2018  2019  2020  2021  2022  2023  2024  Index 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  <20162017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: Re: epicsEventSignal() question
From: Till Straumann <[email protected]>
To: Michael Westfall <[email protected]>, Andrew Johnson <[email protected]>
Cc: [email protected]
Date: Mon, 6 Jun 2016 18:41:48 -0700
On 06/06/2016 05:14 PM, Michael Westfall wrote:
Hi Andrew,

Thanks for the explanation.

We're converting code from vxWorks to OSI (on top of RTEMS), and was wondering what to do with the semFlush() calls that are being used on binary semaphores.  Specifically, we're working on the Allen-Bradley DF1 driver.

Maybe what I should do is have a global counter that each thread increments before calling epicsEventWait(), and have the thread that calls epicsEventSignal() repeatedly signal and decrement the counter till it's zero..

That's probably not that easy. You'd have to increment that counter and block for an event atomically.
This is exactly what a posix condition variable does. The posix implementation uses this mechanism
for the epicsEvent implementation (and pthread_cond_broadcast could be used naturally).

In any case you'll have to be careful: a semaphore has defined semantics (counts the number
of available resources) these no longer hold in a 'broadcast' scenario (how many resources
will become available as a result of a broadcast?).

In a situation where you'd want to broadcast an 'event' or 'condition' reflects the semantics
better than a semaphore: assume you have a number of threads which you want to synchronize
with a condition:

You can have multiple threads waiting for a condition:

/* step 1 */
pthread_mutex_lock( &mtx );

while ( ! event_has_happened ) {
   pthread_cond_wait( &cond, &mtx ); /* step 2a, 2b */
}
pthread_mutex_unlock( &mtx );

/* step 3 */


The sender signals the event:

pthread_mutex_lock( &mtx );
 event_has_happened = 1;
pthread_cond_broadcast( &cond );
pthread_mutex_unlock( &mtx );

With the above synchronization it is ensured that all receiving threads
get to step 3. No matter if they were at step 1 (not testing event yet)
or step 2 past testing 'event_has_happened' and not yet asleep (2a)
or past testing and already asleep (2b) when the sender signalled the
event.

With your counter approach (assuming you atomically
increment/decrement the counter)

receiver:

waiting++
epicsEventWait();

sender:

while ( waiting-- )
  epicsEventSend()

You generate several race conditions:
  - any number of receivers that have not yet incremented the counter
    when the sender signals is never woken up.
  - unless the underlying semaphore is a counting semaphore there may
    be less threads woken up than 'waiting' counted (if e.g., two threads
    have incremented 'waiting' but are not yet asleep and epicsEventSend
    is executed twice then one event is lost).

You *can* implement an event broadcast with elementary epics devices
(epicsEvent, epicsMutex) but you have to be very careful. Any textbook
discusses the implementation of one kind of device by using others.

HTH
- Till



Or is there a better way?



On Mon, Jun 6, 2016 at 4:35 PM, Andrew Johnson <[email protected]> wrote:
Hi Mike,

On 06/06/2016 01:39 PM, Michael Westfall wrote:
> The EPICS Application Developer's Guide says this about event signalling:
> "If multiple threads are waiting on the same event, only one of them
> will be woken when the event is signalled."
>
> How would one go about signalling ALL threads waiting on a particular
> event?
>
> This would be the equivalent of vxWorks semFlush().

Well, not quite. A semFlush() on VxWorks triggers a "thundering herd"
https://en.wikipedia.org/wiki/Thundering_herd_problem but doesn't seem
to allow any task to proceed, since it doesn't actually change the state
of the semaphore. We currently only support uni-processor (UP) on
VxWorks as well, so only one thread can actually proceed at once anyway.

If this were a binary semaphore you would therefore need to call
semGive() [which one to call first?] but only one of the waiting threads
could then return from the semTake() that they would be waiting in since
only one thread can own the semaphore at once; the others would all go
back to sleep even if they were all able to test the semaphore at the
same time (on a UP machine of course they can't).

If it's a counting semaphore instead, you could call semGive() multiple
times to allow multiple threads to return from their semTake() calls,
since there's no API for semGiveMany(int n), but that's going to wake
them up one at a time, not all at once.

The only way I can think of to wake up multiple threads at once would be
using a reader/writer semaphore, and have the semaphore owned by a
writer [taken using semWTake()] with all of the waiting threads sitting
in semRTake(). In this circumstance when the writer calls semGive() it
should then wake up and allow all of the waiting readers to proceed.

EPICS doesn't provide an API for a reader/writer semaphore, in fact we
don't currently provide any way of signalling to wake up more than one
thread at once. On a UP OS like VxWorks you can simulate it using a
regular epicsEvent (which is a binary semaphore on VxWorks) and have
each waiting thread check an associated "broadcast" flag immediately
after epicsEventWait() returns, and if that is set immediately call
epicsEventSignal() with the same ID to wake up the next thread.

This should have almost the same effect as waking all the threads at
once given that only one can actually be running on a UP system anyway,
although the epicsEventSignal() does trigger a system call so isn't free.

Why do you want to do this?

- 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



--
Mike Westfall
Control Systems Software Engineer




References:
epicsEventSignal() question Michael Westfall
Re: epicsEventSignal() question Andrew Johnson
Re: epicsEventSignal() question Michael Westfall

Navigate by Date:
Prev: Re: epicsEventSignal() question Michael Westfall
Next: Re: epicsEventSignal() question Johnson, Andrew N.
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  <20162017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: Re: epicsEventSignal() question Michael Westfall
Next: Re: epicsEventSignal() question Johnson, Andrew N.
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  <20162017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 15 Jul 2016 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·