I have discovered a bug when using cnd_signal() to signal a thread.
cnd_signal() works fine until you signal twice or more in the same critical section. Then the code comes to a dead lock; the thread that sends the signal comes to a stop in the mtx_lock() in the next iterations, while the receiver thread waits for a signal in cnd_wait(). All functions will return thrd_success.
You should be able to call cnd_signal() as many times as you want. As per documentation:
If no threads are blocked, does nothing and returns thrd_success. http://en.cppreference.com/w/c/thread/cnd_signalIf no threads are blocked on the condition variable at the time of the call, the function does nothing and return success. pelles docs
Notes:
-calling cnd_broadcast() after two cnd_signal() will trigger an exception.
-replacing cnd_signal() with cnd_broadcast(), will remove the bug
-pthread_cond_signal() from pthreads has similar description in docs
http://linux.die.net/man/3/pthread_cond_signal-optimization level doesn't matter
-mutex type doesn't matter
#include <stdio.h>
#include <stdlib.h>
#include <threads.h>
#include <assert.h>
#define BUG_ENABLE //disable to get correct behaviour
//#define cnd_signal cnd_broadcast //on the other hand, cnd_broadcast works fine
mtx_t mutex ;
cnd_t cond ;
int run = 0 ;
int unlock = 0 ;
int Test( void* data )
{
( void )data ;
int count = 0 ;
run = 1 ;
while( run )
{
int d = mtx_lock( &mutex ) ;
assert( d == thrd_success ) ;
unlock = 1 ;
d = cnd_wait( &cond , &mutex ) ;
assert( d == thrd_success ) ;
printf("AWAKE %d\n", count++ ) ;
d = mtx_unlock( &mutex ) ;
assert( d == thrd_success ) ;
thrd_yield() ;
}
return 0 ;
}
int main( void )
{
thrd_t thread ;
int d = mtx_init( &mutex , mtx_plain ) ;
assert( d == thrd_success ) ;
d = cnd_init( &cond ) ;
assert( d == thrd_success ) ;
d = thrd_create( &thread , Test , NULL ) ;
assert( d == thrd_success ) ;
while( run == 0 )
thrd_yield() ;
for( int c = 0 ; c < 1000 ; c++ )
{
while( unlock == 0 )
thrd_yield() ;
int d = mtx_lock( &mutex ) ;
assert( d == thrd_success ) ;
d = cnd_signal( &cond ) ;
assert( d == thrd_success ) ;
#ifdef BUG_ENABLE
d = cnd_signal( &cond ) ;
assert( d == thrd_success ) ;
#endif
unlock = 0 ;
d = mtx_unlock( &mutex ) ;
assert( d == thrd_success ) ;
}
printf("DONE\n") ;
while( 1 )
thrd_yield() ;
return 0;
}
I would love to get a confirmation for this.
Thank you.
I have Win7 32 bit, pelles 7.00.355