Linux multithreading practice (6) Use Posix condition variables to solve producer and consumer problems

Source: Internet
Author: User

Linux multithreading practice (6) Use Posix condition variables to solve producer and consumer problems

In the previous article, we have already discussed how to use semaphores to solve the producer and consumer problems. Under what circumstances should we introduce conditional variables?

Assume that there is a shared resource sum, and the associated mutex is lock_s. assume that the sum operation of each thread is very simple and irrelevant to the sum State. For example, it is only sum ++. only mutex is enough. the programmer only needs to ensure that the lock is obtained before each thread operation, sum ++, and unlock. the code for each thread will look like this:

 

add(){   pthread_mutex_lock(lock_s);   sum++;   pthread_mutex_unlock(lock_s);}

 

If the operation is complex, assume that the operation of thread t0, t1, and t2 is sum ++, and thread t3 prints a message when sum reaches 100, and clears sum. in this case, if only mutex is used, t3 requires a loop. In each loop, lock_s is obtained first, and the sum state is checked. If sum> = 100, the data is printed and cleared, then unlock. if sum <100, then unlock and sleep () This thread is appropriate for a period of time.

 

At this time, the code for t0, t1, and t2 remains unchanged. The code for t3 is as follows:

 

print(){   while (1)  {      pthread_mutex_lock(lock_s);      if(sum<100)     {         printf(“sum reach 100!”);         pthread_mutex_unlock(lock_s);     }  else  {       pthread_mutex_unlock(lock_s);       my_thread_sleep(100);       return OK;   } }}

 

There are two problems with this method.

1) sum will not reach 100 in most cases, so for the t3 code, in most cases, it takes the else branch, only lock and unlock, and then sleep (). this wastes CPU processing time.

2) To save CPU processing time, t3 will sleep () for a period of time when the sum has not reached 100. this brings about another problem, that is, the t3 response speed decreases. t4 may wake up when sum reaches 200.

3) in this way, the programmer is in a dilemma when setting sleep () time. It is too short to save resources, and it is too long to reduce the response speed. This is really hard to do!

At this time, the condition variable, falling from the sky, has saved you.

You first define a condition variable.

Pthread_cond_t cond_sum_ready = PTHREAD_COND_INITIALIZER;

T0, t1, and t2 only need to be followed by two lines, like this:

Add () {pthread_mutex_lock (lock_s); sum ++; pthread_mutex_unlock (lock_s); if (sum >=100) pthread_cond_signal (& cond_sum_ready );} the code for t3 is print {pthread_mutex_lock (lock_s); while (sum <100) pthread_cond_wait (& cond_sum_ready, & lock_s); printf ("sum is over 100! "); Sum = 0; pthread_mutex_unlock (lock_s); return OK ;}

Note:

1) Before thread_cond_wait (), you must first lock the associated mutex, because if the target condition is not met, pthread_cond_wait () will actually unlock the mutex, and then block, lock the mutex again after the target condition is met, and then return.

2) Why is it while (sum <100) instead of if (sum <100 )? This is because there is a time difference between pthread_cond_signal () and pthread_cond_wait (). In this case, there is another thread t4 that reduces sum to less than 100, after pthread_cond_wait () is returned, t3 should check the sum size again. this is the intention of using while.


The synchronization technology between threads mainly focuses on mutex locks and condition variables. The combination of condition variables and mutex can well handle the synchronization problem between threads waiting for conditions.

Common Posix conditional variables APIs:

 

int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);  int pthread_cond_destroy(pthread_cond_t *cond);    int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);  int pthread_cond_timedwait(pthread_cond_t *cond,  pthread_mutex_t  *mutex,  const  struct timespec *abstime);    int pthread_cond_signal(pthread_cond_t *cond);  int pthread_cond_broadcast(pthread_cond_t *cond); 

Generally, condition variables must be used together with mutex locks to protect condition variables by mutex. condition detection is performed under the protection of mutex locks. If a condition is false, a thread automatically blocks and releases the mutex lock waiting for the State to change. If another thread changes the condition, it sends a signal to the associated condition variable and wakes up one or more threads waiting on the condition variable. These threads will obtain the mutex again, reevaluate the condition. If you place the condition variables in the shared memory, and the two processes can share the read/write memory, the condition variables can be used to achieve thread synchronization between the two processes.

 

Usage specification of condition variables:

 

(1) Wait for the condition code pthread_mutex_lock (& mutex); while (the condition is false) pthread_cond_wait (cond, mutex); Modify the condition pthread_mutex_unlock (& mutex); (2), send the notification code pthread_mutex_lock (& mutex) to the condition; set the condition to pthread_cond_signal (cond); pthread_mutex_unlock (& mutex );
Note that while, rather than if, is still running properly after the signal is interrupted.

 

Solve the producer consumer problem (unbounded buffer zone ):

 

#include 
 
  #include 
  
   #include 
   
    #include 
    
     #include 
     
      #include 
      
       #include 
       
        #include 
        
         #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0)#define CONSUMERS_COUNT 2#define PRODUCERS_COUNT 1pthread_mutex_t g_mutex;pthread_cond_t g_cond;pthread_t g_thread[CONSUMERS_COUNT + PRODUCERS_COUNT];int nready = 0;void *consume(void *arg){ int num = (int)arg; while (1) { pthread_mutex_lock(&g_mutex); while (nready == 0) { printf("%d begin wait a condtion ...\n", num); pthread_cond_wait(&g_cond, &g_mutex); } printf("%d end wait a condtion ...\n", num); printf("%d begin consume product ...\n", num); --nready; printf("%d end consume product ...\n", num); pthread_mutex_unlock(&g_mutex); sleep(1); } return NULL;}void *produce(void *arg){ int num = (int)arg; while (1) { pthread_mutex_lock(&g_mutex); printf("%d begin produce product ...\n", num); ++nready; printf("%d end produce product ...\n", num); pthread_cond_signal(&g_cond); printf("%d signal ...\n", num); pthread_mutex_unlock(&g_mutex); sleep(1); } return NULL;}int main(void){ int i; pthread_mutex_init(&g_mutex, NULL); pthread_cond_init(&g_cond, NULL); for (i = 0; i < CONSUMERS_COUNT; i++) pthread_create(&g_thread[i], NULL, consume, (void *)i); sleep(1); for (i = 0; i < PRODUCERS_COUNT; i++) pthread_create(&g_thread[CONSUMERS_COUNT + i], NULL, produce, (void *)i); for (i = 0; i < CONSUMERS_COUNT + PRODUCERS_COUNT; i++) pthread_join(g_thread[i], NULL); pthread_mutex_destroy(&g_mutex); pthread_cond_destroy(&g_cond); return 0;}
        
       
      
     
    
   
  
 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.