简体   繁体   中英

Condition Variable POSIX Thread : C/C++

I am learning Multithreading. With regard to

http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html#SCHEDULING

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>


pthread_mutex_t count_mutex     = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  condition_var   = PTHREAD_COND_INITIALIZER;



void *functionCount1();
void *functionCount2();

int  count = 0;

#define COUNT_DONE  10
#define COUNT_HALT1  3
#define COUNT_HALT2  6



main()
{
   pthread_t thread1, thread2;
   pthread_create( &thread1, NULL, &functionCount1, NULL);
   pthread_create( &thread2, NULL, &functionCount2, NULL);



   pthread_join( thread1, NULL);
   pthread_join( thread2, NULL);

   printf("Final count: %d\n",count);

   exit(0);
}



// Write numbers 1-3 and 8-10 as permitted by functionCount2()

void *functionCount1()
{
   for(;;)
   {
      // Lock mutex and then wait for signal to relase mutex
      pthread_mutex_lock( &count_mutex );



      // Wait while functionCount2() operates on count
      // mutex unlocked if condition varialbe in functionCount2() signaled.

      pthread_cond_wait( &condition_var, &count_mutex );

      count++;

      printf("Counter value functionCount1: %d\n",count);
      pthread_mutex_unlock( &count_mutex );

      if(count >= COUNT_DONE) return(NULL);
    }
}



// Write numbers 4-7



void *functionCount2()
{
   for(;;)
    {
       pthread_mutex_lock( &count_mutex );

       if( count < COUNT_HALT1 || count > COUNT_HALT2 )
       {
          // Condition of if statement has been met.
          // Signal to free waiting thread by freeing the mutex.
          // Note: functionCount1() is now permitted to modify "count".

          pthread_cond_signal( &condition_var );
       }
       else
       {
          count++;
          printf("Counter value functionCount2: %d\n",count);
       }



       pthread_mutex_unlock( &count_mutex );

       if(count >= COUNT_DONE) return(NULL);
    }
}

I want to know the control flow of the code.

As pthread_cond_wait - unlocks the mutex and waits for the condition variable cond to be signaled

What I understood about the control of flow is

1) Thread One,Two are created and thread1 is passed the control (considering Single Core Processor System)

2) When it encounters pthread_cond_wait( &condition_var, &count_mutex ); in thread1 routine void *functionCount1() - it releases the lock and goes to wait state passing control to thread2 void *functionCount1()

3) In thread2 variable count is checked and since it satisfies count < COUNT_HALT1 || count > COUNT_HALT2 count < COUNT_HALT1 || count > COUNT_HALT2 - it signals thread1 and restarts is to increment count

4) Steps 2 to 3 is repeated which displays 1-3 by thread1

5) For count 4-7 the thread2 is in action and there is no switching between thread1 and thread2

6)For count 8-10 again steps 2-3 are repeated.

I want to know whether my understanding is correct? Does thread1 goes to sleep and thread2 wakes it up ( ie threads are switched) for count value 1-3 and 8-10 ie switching between threads happen 5 times ?

EDIT

My main concern to ask this question is to know if thread1 will go to sleep state when it encounters pthread_cond_wait( &condition_var, &count_mutex ); and won't be active again unless signalled by thread2 and only then increments count ie it is not going to increment 1-3 in one go rather for each increment , it has to wait for signal from thread2 only then it can proceed further

First: get the book by Butenhof, and study it. The page you cite is incorrect in several places, and the author obviously doesn't understand threading himself.

With regards to your questions: the first thing to say is that you cannot know about the control flow of the code. That's a characteristic of threading, and on modern processors, you'll often find the threads really running in parallel, with one core executing one thread, and another core another. And within each thread, the processor may rearrange memory accesses in unexpected ways. This is why you need mutexes, for example. (You mention "considering single core processing system", but in practice, single core general purpose systems don't exist any more.)

Second, how the threads are scheduled is up to the operating system. In your code, for example, functionCount2 could run until completion before functionCount1 starts, which would mean that functionCount1 would wait forever.

Third, a thread in pthread_cond_wait may wake up spuriously. It is an absolute rule that pthread_cond_wait be in a loop, which checks whatever condition you're actually waiting for. Maybe something like:

while ( count > COUNT_HALT1 && count < COUNT_HALT2 ) {
    pthread_cond_wait( &condition_var, &count_mutex );
}

Finally, at times, you're accessing count in a section not protected by the mutex. This is undefined behavior; all accesses to count must be protected. In your case, the locking and unlocking should probably be outside the program loop, and both threads should wait on the conditional variable. (But it's obviously an artificial situation—in practice, there will almost always be a producer thread and a consumer thread.)

In the ideal world, yes, but, in practice, not quite.

You can't predict which tread takes control first. Yes, it's likely to be thread1 , but still not guaranteed. It is the first racing condition in your code.

When thread2 takes control, most likely it will finish without stopping. Regardless of how many CPUs you have. The reason is that it has no place to yield unconditionally . The fact you release mutex , doesn't mean any1 can get a lock on it. Its the second racing condition in your code.

So, the thread1 will print 11 , and that is the only part guaranteed.

1) Threads are created. Control is not passed to thread1, it's system scheduler who decides which thread to execute. Both threads are active, both should receive processor time, but the order is not determined. There might be several context switches, you don't really control this.

2) Correct, thread1 comes to waiting state, thread2 continues working. Again, control is not passed explicitly.

3) Yes, thread2 notifies condition variable, so thread1 will awake and try to reacquire the mutex. Control does not go immediately to thread1.

In general you should understand that you can't really control which thread to execute; it's job os the system scheduler, who can put as many context switches as it wants.

UPD: With condition variables you can control the order of tasks execution within multithreading environment. So I think your understanding is more or less correct: thread1 is waiting on condition variable for signal from thread2. When signal is received thread1 continues execution (after it reacquires the mutex). But switching between threads - there might be many of them, 5 is just a theoretical minimum.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM