I. Overview
In the previous article, we introduced the mutex amount. The conditional variable is different from the mutex, and the mutex protects the critical section by preventing multiple threads from accessing the shared mutex at the same time . A condition variable is a thread that can be used to tell other threads that a state has changed, so that threads waiting on the condition variable continue to execute. In layman's terms : Setting a condition variable allows thread 1 to wait at the front of a critical section, and when other threads perform a notification operation on that variable, thread 1 is awakened and continues to execute downward.
The condition variable is always used with the mutex, and the mutex protects the condition variable, preventing multiple threads from competing against the condition variable. And so will write a small example, see how they work together!
Two. Function interface
1. Initializing condition variables
1.1: Macro Constant initialization
1 pthread_cond_t cond = Pthread_cond_initializer;
1.2: Function Initialization
1 #include <pthread.h>23intconst pthread_condattr_t *restrict attr);
Similar to mutex, cond is a structural pointer to a conditional variable, and attr is a struct pointer to a conditional variable property.
2. Wait and notify condition variables
1 #include <pthread.h>2 Span style= "color: #008080;" >3 int pthread_cond_timedwait (pthread_cond_t *restrict cond, Pthread_ mutex_t *restrict Mutex, const struct Timespec *restrict abstime); 4 restrict mutex); 5 int pthread_cond_broadcast (pthread_cond_t *cond); 7
Wait for the function to pass in a mutex. Pthread_cond_timewait () can specify a time to wait and return a etimedout error If the specified time has not been notified. and pthread_cond_wait () will always block .
The notification function, pthread_cond_signal () wakes at least one waiting thread, and pthread_cond_broadcast () wakes all threads on that condition variable.
3. Destroying condition variables
1 #include <pthread.h>23int Pthread_cond_destroy (pthread_cond_t *cond);
Three. A simple example
We still use an example of a mutex. When the mutex is used alone, some threads need to get a certain state, it is necessary to enter and exit the critical section multiple times , and the locking of the mutex frequently causes the waste of system resources . The following combination of conditional variables solves this problem:
1 /**2 * @file pthread_mutex.c3 */4 5#include <stdio.h>6#include <stdlib.h>7#include <string.h>8#include <unistd.h>9#include <pthread.h>Ten One /*define the mutex amount*/ A pthread_mutex_t MTX; - /*Mutex Property*/ - pthread_mutexattr_t mtx_attr; the /*Global Resources*/ - intMoney ; - - /*condition Variable*/ +pthread_cond_t cond =Pthread_cond_initializer; - + voidErr_exit (Const Char*err_msg) A { atprintf"error:%s\n", err_msg); -Exit1); - } - - /*Thread Functions*/ - void*thread_fun (void*Arg) in { - while(1) to { + /*Locking*/ -Pthread_mutex_lock (&MTX); the * /*condition Variable*/ $ while(Money >0)Panax Notoginseng { -printfthe child threadWaiting for money equals 0...\n"); thePthread_cond_wait (&cond, &MTX); + } A theprintf"child threads entering the critical section view money\n"); + if(Money = =0) - { $Money + = $; $printf"Child Thread: Money =%d\n", money); - } - the /*Unlock*/ -Pthread_mutex_unlock (&MTX);Wuyi theSleep1); - } Wu - returnNULL; About } $ - intMainvoid) - { - pthread_t tid; A + /*Initialize Mutex property*/ the if(Pthread_mutexattr_init (&mtx_attr) = =-1) -Err_exit ("Pthread_mutexattr_init ()"); $ the /*set the Mutex property*/ the if(Pthread_mutexattr_settype (&mtx_attr, pthread_mutex_normal) = =-1) theErr_exit ("Pthread_mutexattr_settype ()"); the - /*Initialize Mutex amount*/ in if(Pthread_mutex_init (&MTX, &mtx_attr) = =-1) theErr_exit ("Pthread_mutex_init ()"); the About /*Create a thread*/ the if(Pthread_create (&tid, NULL, thread_fun, NULL) = =-1) theErr_exit ("pthread_create ()"); the +Money = +; - while(1) the {Bayi /*Locking*/ thePthread_mutex_lock (&MTX); the - if(Money >0) - { theMoney-= -; theprintf"Main thread: Money =%d\n", money); the } the - /*Unlock*/ thePthread_mutex_unlock (&MTX); the the /*If money = 1, the child thread is notified*/94 if(Money = =0) the { theprintf"notify child thread \ n"); thePthread_cond_signal (&cond);98 } About -Sleep1);101 }102 103 return 0;104}
The code is almost the same as the previous example, adding a conditional variable. Compile run:
You can see that the wait condition variable on line 39th is triggered, and the child thread waits until the main thread notifies it. In this way, threads do not frequently enter the critical section, and frequently lock and unlock.
Four. In-depth knowledge
1. Wait for the function to pass in a mutex, this mutex will occur in this function call will be the following changes: When the function was just called, it will unlock the mutex, and then let the calling thread block , unlock the other threads Have a chance to get this lock. When a thread invokes the notification function, the function receives a notification, locking the mutex, and then continues to operate the critical section. Visible this design is very reasonable!!!
2. The wait function of the condition variable is surrounded by a while loop , and the 36th line of the program. Cause: If there are multiple threads waiting for this conditional variable to close the mutex , when the condition variable is notified, the next step is to lock the mutex, but in this very small time difference , other threads preempt Gets the mutex and enters the critical section to change a state. At this point the condition variable should continue to judge the state that the other person has just been first modified, that is, continue to execute while. There is a reason to prevent false notification, after receiving false notification, as long as the conditions inside the true, continue to hibernate!!!
Linux thread Synchronization (2)-Condition variables