pthread wait on multiple conditions

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

pthread wait on multiple conditions

Lee Revell
Not a JACK question but this list has many pthreads experts...

What's the best interface for a thread to wait on multiple conditions,
like select() for FDs?  Do I have to associate a single condition
variable with all of the events I am interested in, then on wakeup check
which event occurred?

Lee



-------------------------------------------------------
SF.Net email is sponsored by:
Tame your development challenges with Apache's Geronimo App Server. Download
it for free - -and be entered to win a 42" plasma tv or your very own
Sony(tm)PSP.  Click here to play: http://sourceforge.net/geronimo.php
_______________________________________________
Jackit-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/jackit-devel
Reply | Threaded
Open this post in threaded view
|

Re: pthread wait on multiple conditions

torbenh
On Sat, Nov 12, 2005 at 01:32:19AM -0500, Lee Revell wrote:
> Not a JACK question but this list has many pthreads experts...
>
> What's the best interface for a thread to wait on multiple conditions,
> like select() for FDs?  Do I have to associate a single condition
> variable with all of the events I am interested in, then on wakeup check
> which event occurred?

i would model my app like a thread waiting on queue and processing the
event.
then add a framework to register as listener to some events.
and

post_event( event )
{
   for i in registered queues:
      push_event( event, i );
}


though you need a pre allocated memory pool to make this realtime
safe...


--
torben Hohn
http://galan.sourceforge.net -- The graphical Audio language


-------------------------------------------------------
SF.Net email is sponsored by:
Tame your development challenges with Apache's Geronimo App Server. Download
it for free - -and be entered to win a 42" plasma tv or your very own
Sony(tm)PSP.  Click here to play: http://sourceforge.net/geronimo.php
_______________________________________________
Jackit-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/jackit-devel
Reply | Threaded
Open this post in threaded view
|

Re: pthread wait on multiple conditions

Fons Adriaensen
In reply to this post by Lee Revell
On Sat, Nov 12, 2005 at 01:32:19AM -0500, Lee Revell wrote:

> What's the best interface for a thread to wait on multiple conditions,
> like select() for FDs?  Do I have to associate a single condition
> variable with all of the events I am interested in, then on wakeup check
> which event occurred?

If you wait on multiple events, there could be more than one ready at
the time you wake up, and in that case you need to have some idea of
'priority' to select one of them to be processed first. In that sense,
you always have to check the events. But you can easily arrange for
not being woken up by events that you are not (in that particular state)
interested in. Alll it takes is a mask that is checked by the senders.


This is how I do it in libclthreads (its C++, but easy).


Bmutex is just an abstraction of a Posix mutex:

class Bmutex
{
public:

    Bmutex (void) { if (pthread_mutex_init (&_mutex, 0)) abort (); }
    ~Bmutex (void) { pthread_mutex_destroy (&_mutex); }
    Bmutex (const Bmutex&);  // disabled
    Bmutex& operator= (const Bmutex&); // disabled

    void lock (void) { if (pthread_mutex_lock (&_mutex)) abort (); }
    void unlock (void){ if (pthread_mutex_unlock (&_mutex)) abort (); }
    int trylock (void) { return pthread_mutex_trylock (&_mutex); }

private:

    friend class Esync;

    pthread_mutex_t  _mutex;
};


Esync derives for Bmutex (it could equally well just contain one), and
adds the condition variable:


class Esync : public Bmutex
{
public:

    enum
    {
        EM_ALL   = ~0,
        EV_TIME  = -1,
        EV_ERROR = -2
    };

    Esync (void) : _event (EV_ERROR), _emask (0) { if (pthread_cond_init (&_cond, 0)) abort (); }
    ~Esync (void) { pthread_cond_destroy (&_cond); }
    Esync (const Esync&);
    Esync& operator= (const Esync&);

    void eput (int e);
    int  eget (unsigned int m = EM_ALL, const timespec *t = 0);

private:
 
    volatile int     _event;
    unsigned int     _emask;
    pthread_cond_t   _cond;
};


inline void Esync::eput (int e)
{
    if ((1 << e) & _emask)
    {
        _event = e;
        if (pthread_cond_signal (&_cond)) abort ();
    }
}


inline int Esync::eget (unsigned int m, const timespec *t)
{
    int r;
   
    _event = EV_ERROR;
    _emask = m; // the set of events to wait for
    do
    {  
        if (t) r = pthread_cond_timedwait (&_cond, &_mutex, t);
        else   r = pthread_cond_wait (&_cond, &_mutex);

        // Wait ...
         
        if (_event >= 0) break;
        if (r == ETIMEDOUT)
        {
            _event = EV_TIME;
            break;
        }
    }
    while (r == EINTR); // skip false wakeups from signals

    _emask = 0; // we just got an event, and are no longer waiting
    return _event;
}

The important things here are the eget() and eput() members, and
the _emask that represents the set of events the receiver is waiting
for (one event type per bit). The eget() can be used with or without
a timeout.

Esync in turn is used as building block for higher level things,
such as the ITC_ctlr class that contains 16 mail queues and 16
counting semaphores, and that is used by the threads classes.


The logic here is this (see ITC_ctrl for a concrete example):

When a receiver wants to receive one of the events in the set E,
and if none are available wait for them, this happens:

1. Lock the mutex in the Esync (to protect any shared data
   structures, including the data members of the Esync).

2. Check the availability of events in some order that defines
   their priority.

3. If an event in the set E is available, do whatever is required
   to get it 'out of the protected area', unlock the mutex and return.
   Else call eget(E). This will deschedule the thread.

4. When eget(E) wakes up, the return value indicates the type
   of event that is available. Again, get it 'out the protected
   area', unlock and return.


When a sender transmits an event, this happens:

1. Lock the mutex, put the event 'into the protected area',
   e.g. add a message to a linked list.

2. Call eput() with as argument the event type that was just
   added. Within eput() the _emask is checked, and if the
   receiver was waiting for it, it is woken up.

3. Unlock the mutex.



To get non-blocking versions (that may fail), use trylock()
instead of lock() in the surrounding object, and if necessary
report failure instead of calling eget()/eput().

--
FA


















-------------------------------------------------------
SF.Net email is sponsored by:
Tame your development challenges with Apache's Geronimo App Server. Download
it for free - -and be entered to win a 42" plasma tv or your very own
Sony(tm)PSP.  Click here to play: http://sourceforge.net/geronimo.php
_______________________________________________
Jackit-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/jackit-devel