MUTEX and CONDVAR

Hello,

I’d like to signal condition changes in an other way as it is described in
the “Getting Started” book from Rob Krten. In the book he uses the following
order for the “producer” and the “consumer” of data:

consumer / producer:

while(1)
{
pthread_mutex_lock( &mutex );
while( !condition ) // while( condition )
{
pthread_cond_wait( &condvar, &mutex );
}

condition = 1; // condition = 0;
pthread_cond_signal( &condvar );
pthread_mutex_unlock( &mutex );
}


I’d like to use the following producer and consumer (you will notice the
missing pthread_mutex_lock and pthread_mutex_unlock and pthread_cond_wait
functions in the producer and the missing pthread_cond_signal in the
consumer):

producer (INTERRUPT called by hardware when new data present):

{

condition = 1;
pthread_cond_signal( &condvar );
}

consumer:

while(1)
{
pthread_mutex_lock( &mutex );
while( !condition )
{
pthread_cond_wait( &condvar, &mutex );
}

condition = 0;
pthread_mutex_unlock( &mutex );
}

When I run the system like this, QNX sometimes hangs. Do I always have to
use the full set of functions? Are there some restrictions that exclude this
type of usage of these functions?

Regards.

Nnamdi

Nnamdi Kohn wrote:

I’d like to use the following producer and consumer (you will notice the
missing pthread_mutex_lock and pthread_mutex_unlock and pthread_cond_wait
functions in the producer and the missing pthread_cond_signal in the
consumer):

producer (INTERRUPT called by hardware when new data present):

{

condition = 1;
pthread_cond_signal( &condvar );
}

Clipped from the online docs for the function pthread_cond_signal

------------------------Safety:

Cancellation point No
Interrupt handler No
Signal handler Yes
Thread Yes

Note the entry for “Interrupt Handler” safety.

That explains the hang.

The correct way to accomplish what you want is by returning a pulse from
the interrupt handler. I don’t have Robs’ book, but I’d be surprised if
it doesn’t cover this.

Rennie

“Rennie Allen” <rallen@csical.com> schrieb im Newsbeitrag
news:3F7301FC.6080107@csical.com

Nnamdi Kohn wrote:

I’d like to use the following producer and consumer (you will notice the
missing pthread_mutex_lock and pthread_mutex_unlock and
pthread_cond_wait
functions in the producer and the missing pthread_cond_signal in the
consumer):

producer (INTERRUPT called by hardware when new data present):

{

condition = 1;
pthread_cond_signal( &condvar );
}

Clipped from the online docs for the function pthread_cond_signal

------------------------Safety:

Cancellation point No
Interrupt handler No
Signal handler Yes
Thread Yes

Note the entry for “Interrupt Handler” safety.

That explains the hang.

The correct way to accomplish what you want is by returning a pulse from
the interrupt handler. I don’t have Robs’ book, but I’d be surprised if
it doesn’t cover this.

Rennie

Thanks Rennie,

is the delivery of a pulse not much slower (because it is coupled with a
copying of data between two threads or processes) than the mutex-solution?
By the way, the producer is not a real INTERRUPT but rather a callback
Function from a communication interface driver. Does this matter?

Nnamdi

Nnamdi Kohn wrote:

Thanks Rennie,

is the delivery of a pulse not much slower (because it is coupled with a
copying of data between two threads or processes) than the mutex-solution?

What do you call slow ? A pulse (with the highest prio of course) might
take a microsecond (probably less) on a 233Mhz PII class machine. Perhaps
signalling a condvar would theoretically be faster, but the fact that it
is simply wrong to call it from interrupt context makes any theoretical
performance advantage moot. If your really concerned with minimizing
scheduling latency, simply have a dedicated thread that does an
InterruptWait on the interrupt, and do everything in that thread.

By the way, the producer is not a real INTERRUPT but rather a callback
Function from a communication interface driver. Does this matter?

What is the context of the callback ? If it is called at interrupt time, it
definately matters. Incidentally, if you are porting a driver that installed
user callbacks into the interrupt handler, it is easy to decouple this, and
have them called at process time. Simply change each line in the interrupt
handler where the callback code is invoked to instead set the value of the
“data payload” member of the pulse to the address of the callback that would
have been called. In the pulse handler at process time, simply call the code
at the address given in the pulse payload.

Rennie

“Nnamdi Kohn” <nnamdi.kohn@tu-bs.de> wrote in message
news:bkuhu6$mfq$1@inn.qnx.com

Hello,

I’d like to signal condition changes in an other way as it is described in
the “Getting Started” book from Rob Krten. In the book he uses the
following
order for the “producer” and the “consumer” of data:

consumer / producer:

while(1)
{
pthread_mutex_lock( &mutex );
while( !condition ) // while( condition )
{
pthread_cond_wait( &condvar, &mutex );
}

condition = 1; // condition = 0;
pthread_cond_signal( &condvar );
pthread_mutex_unlock( &mutex );
}


I’d like to use the following producer and consumer (you will notice the
missing pthread_mutex_lock and pthread_mutex_unlock and pthread_cond_wait
functions in the producer and the missing pthread_cond_signal in the
consumer):

producer (INTERRUPT called by hardware when new data present):

{

condition = 1;
pthread_cond_signal( &condvar );
}

Not sure what are you trying to achieve, but this is unsafe way to use
condvars. Your producer can signal the condvar when the consumer is not in
the position to receive it (that is, not sitting in the
pthread_condvar_wait). Such signal (note the word ‘signal’ here refers to
the specific meaning related to condvars, NOT to the Unix signals) will be
lost. If this is your deliberate choice, you might be ok, otherwise your
code might deadlock. This is the reason why you need to pass a mutex into
pthread_condvar_wait() and why you need to lock the mutex before signaling a
condvar - that way the call to pthread_condvar_signal() will block until the
mutex is unlocked (by entering into pthread_condvar_wait in another thread)
so you are not going to miss any signals.

consumer:

while(1)
{
pthread_mutex_lock( &mutex );
while( !condition )
{
pthread_cond_wait( &condvar, &mutex );
}

condition = 0;
pthread_mutex_unlock( &mutex );
}

Since you have removed the signaling part from the consumer, you do not need
mutex lock/unlock inside the loop - they are serving no purpose. The mutex
needs to be locked before you enter the loop. It will be unlocked implicitly
every time you enter into pthread_cond_wait() and locked implicitly again
just before you return from it.

You also need to check for the return code in the inner loop - the reason
why there is an inner loop at all is that pthread_condvar_wait (like most
other blocking functions) may be interrupted by an asynchronous Unix signal
(note the different meaning of the word ‘signal’ here) resulting in a
spurious wakeup. So if the errno is EINTR you should stay in the loop,
otherwise you are better off baling out with error - if the code failed with
a different errno it is likely to keep failing and you will have a runaway
thread.

When I run the system like this, QNX sometimes hangs. Do I always have to
use the full set of functions? Are there some restrictions that exclude
this
type of usage of these functions?

It is hard to say what exactly you need unless you say what you’re trying to
achieve. If you really have a producer passing some data to a consumer, you
need to synchronize them both ways - the consumer needs to know when there’s
new piece of data to consume (assuming the data is in some global buffer)
and the producer needs to know when it can put a new piece of data into that
buffer (i.e., whether or not the consumer has already consumed the previous
piece). That is why both producer and consumer signal each other. I am
speculating, but with code like that you could be failing to actually
syncrhonize read and write access to the buffer and that could incidentally
cause your system to hang (by stuffing the resulting garbage into some
sensitive place). It is even more likely that your code will hang (and if it
runs on high priority that will look like a system hang).

Some good book explaining POSIX synchronisation concepts would help a lot.

– igor

Igor Kovalenko <kovalenko@attbi.com> wrote:

You also need to check for the return code in the inner loop - the reason
why there is an inner loop at all is that pthread_condvar_wait (like most
other blocking functions) may be interrupted by an asynchronous Unix signal
(note the different meaning of the word ‘signal’ here) resulting in a
spurious wakeup. So if the errno is EINTR you should stay in the loop,

Not exactly. POSIX says that if a signal interrupts pthread_cond_wait()
and causes it to return, the returned value is zero:

If a signal is delivered to a thread waiting for a condition
variable, upon return from the signal handler the thread resumes
waiting for the condition variable as if it was not interrupted, or
it shall return zero due to spurious wakeup.

These functions shall not return an error code of [EINTR].

(BTW Just to make sure it’s clear: pthread_cond_wait() does not set
the global variable errno – it returns a non-zero error code on
failure. It’s that code that you were referring to as “the errno”,
right Igor? :slight_smile:

otherwise you are better off baling out with error - if the code failed with
a different errno it is likely to keep failing and you will have a runaway
thread.

Right: it’s probably safe to assume that if it fails, you don’t have a
reliable way to recover. Most possible reasons for pthread_cond_wait()
to fail are bugs in your code.

“Wojtek Lerch” <wojtek_l@yahoo.ca> wrote in message
news:bl9h63$jdd$1@inn.qnx.com

Igor Kovalenko <> kovalenko@attbi.com> > wrote:
You also need to check for the return code in the inner loop - the
reason
why there is an inner loop at all is that pthread_condvar_wait (like
most
other blocking functions) may be interrupted by an asynchronous Unix
signal
(note the different meaning of the word ‘signal’ here) resulting in a
spurious wakeup. So if the errno is EINTR you should stay in the loop,

Not exactly. POSIX says that if a signal interrupts pthread_cond_wait()
and causes it to return, the returned value is zero:

If a signal is delivered to a thread waiting for a condition
variable, upon return from the signal handler the thread resumes
waiting for the condition variable as if it was not interrupted, or
it shall return zero due to spurious wakeup.

These functions shall not return an error code of [EINTR].

(BTW Just to make sure it’s clear: pthread_cond_wait() does not set
the global variable errno – it returns a non-zero error code on
failure. It’s that code that you were referring to as “the errno”,
right Igor? > :slight_smile:

When I think about it, I can remember that pthread functions generally
return errors directly rather than set the errno. But the habit is strong
and when I am not paying attention …

Thanks Wojtek
– igor