glibc and Thread synchronization

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



/*
Hi all,
As I'm somewhat relatively new to Linux Threads, I 'm trying to get some help to
circumvent
the issue described below (though not 100% sure I knocked on the right door).
Plateform: linux 2.4.21-0.13mdk
]$gcc --version
gcc (GCC) 3.2.2 (Mandrake Linux 9.1 3.2.2-3mdk)
glibc-2.3.1-10.1.91mdk

To get appropriate thread synchronization, I'm using the usual mutex/condition
variable duo, that is:
Thread 0
              pthread_mutex_lock(&mut);
              pthread_cond_wait(&cond, &mut);
              ....do something on x,y ....
              pthread_mutex_unlock(&mut);
Thread 1
              pthread_mutex_lock(&mut);
	      ....do other things on x,y ....
              if (x > y) pthread_cond_signal(&cond);
              pthread_mutex_unlock(&mut);

The above code is inspired from "man pthread_cond_wait" output

In somecases, this snippet works as expected (if Thread 0 locks the  mutex
first). However, should thread 1
gets the lock on mutex "mut" first, and depending on the timeslice assigned to
each thread (over which there is very few control at the user level),
it can happen that Thread 0 never get the condition signaled. For example:

Thread 1 is getting the lock on muttex mut first
Thread 0 tries to lock mut; as it is already locked, the thread is put asleep.
Thread 1 do the job; when done, the condition is signaled, and the mutex is
unlocked.

However, since there was no thread waiting for the condition when it was
signaled, nothing happens, and thread 0
gets stuck on pthread_cond_wait(&cond, &mut). On my system, the behavior is the
same if pthread_cond_signal(&cond)
is called after pthread_mutex_unlock(&mut), or if I loop in a _trylock in Thread
0. The only solution I found is
to change :
              pthread_mutex_lock(&mut);
	      ....do other things on x,y ....
              if (x > y) pthread_cond_signal(&cond);
              pthread_mutex_unlock(&mut);
into
              pthread_mutex_lock(&mut);
	      ....do other things on x,y ....
              pthread_mutex_unlock(&mut);
	      usleep(1);
              if (x > y) pthread_cond_signal(&cond);

But this is obviously not a smart solution, since x and y could be modified as
soon as the mutex is unlock.

I think this issue is intrisinc to linux thread design, since the signal is lost
if there is no thread waiting
for it. However, this is still enoying because, in my view, it breaks the
expected deterministic behavior
resulting from thread synchronization. I've added below a small, dummy code,
that reproduces the problem.

What I'm looking for is a condition that remains signaled until a thread
eventually reset it (equivalent to an
event in windows world). Has anyone ever found the trick or succeeded into
circumventing this problem ?
Any imputs are most welcomed

Alexis

*/
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
void *thread_function(void *);
void *thread_reader(void *);
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

int  counter = 0;
void  *thread_function(void* p)
{
   pthread_mutex_lock( &mutex1 );
   fprintf(stdout,"Thread number %ld WAITING CONDITION for counter \n",
pthread_self());fflush(stdout);
   pthread_cond_wait(&cond,&mutex1);
   counter++;
   pthread_mutex_unlock( &mutex1 );
   fprintf(stdout,"Thread number %ld has INCREMENTED counter \n",
pthread_self());fflush(stdout);
   pthread_exit((void*)0);
}
void  *thread_reader(void* p)
{  
   pthread_mutex_lock( &mutex1 );
   fprintf(stdout,"Thread number %ld is READING counter %d\n", pthread_self(),
counter);fflush(stdout);
   pthread_mutex_unlock( &mutex1 );
   //usleep(1); /* required for thread_function to have condition cond signaled...*/
   pthread_cond_signal(&cond);
   fprintf(stdout,"Thread number %ld has RED counter %d\n", pthread_self(),
counter);fflush(stdout);

   pthread_exit((void*)0);
}

int main(int argc, char *argv[])
{
  #define NTHREADS 2
  int status,rc;
  void * (*f0)(void* args);
  void * (*f1)(void* args);
  pthread_t thread_id[NTHREADS];
  pthread_attr_t attr;
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);


  /* Substitute f1,f0 address to see the stuff */
  f1 = thread_function;
  f0 = thread_reader;


		rc = pthread_create( &thread_id[0], &attr, f0, NULL );
			if (rc)
		{
			printf("ERROR; return code from pthread_create  is %d\n", rc);
			exit(-1);
		}

		rc = pthread_create( &thread_id[1], &attr, f1, NULL );
				if (rc)
		{
			printf("ERROR; return code from pthread_create  is %d\n", rc);
			exit(-1);
		}
	/** Joignin the thread*/
  	 pthread_attr_destroy(&attr);
		rc = pthread_join(thread_id[0], (void **)&status);
		if (rc)
		{
			printf("ERROR; return code from pthread_join()  is %d for thread %ld\n",
rc,thread_id[0]);
			exit(-1);
		}
      printf("Completed join with thread %ld status= %d\n",thread_id[0],
status);fflush(stdout);

		rc = pthread_join(thread_id[1], (void **)&status);
		if (rc)
		{
			printf("ERROR; return code from pthread_join()  is %d for thread %ld\n",
rc,thread_id[1]);
			exit(-1);
		}
     printf("Completed join with thread %d status= %d\n",thread_id[1],
status);fflush(stdout);



   printf("Final counter value: %d\n", counter);
   }



[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux