"Copyright Notice: respect for the original, reproduced please retain the source: blog.csdn.net/shallnet or .../gentleliu, the article is for learning communication only, do not use for commercial purposes"in the previous section, when it comes to the mutex of a thread, the mutex is good for preventing access to a shared variable, and this section looks at how two threads can synchronize. A mutex can also implement thread synchronization, and when the value satisfies a certain condition, it continues polling when the front thread continues, but it is quite a waste of CPU time. What we need is for a thread to go to sleep, and when the thread executes the condition, the other thread proactively notifies it, which is the condition variable we're going to say in this section, which is often used with mutexes. As with semaphores, a thread can perform a wait operation on a condition variable. If thread A is waiting for a condition variable, it will be blocked until another thread B sends a signal to the same condition variable to change its state. Unlike semaphores, where the condition variable does not have a count value and does not occupy the memory space, thread A must start waiting before B sends the signal. If B sends a signal before a wait operation, the signal is lost, and A is blocked until another thread sends the signal to the condition variable again.
The condition variable will allow you to do this by ordering the thread to continue running in one case, while the other is ordering the thread to block. As long as each thread that may involve changing the state correctly uses the condition variable, Linux will guarantee that the line threads can be activated when the condition is changed due to the state of a condition variable being blocked.
Gnu/linux just provides this mechanism, and each condition variable must be used in conjunction with a mutex to prevent this competitive state from occurring. In this design, the threading function should follow these steps:
- Thread_function first locks the mutex and reads the value of the flag variable.
- If the flag variable is already set, the thread unlocks the mutex and executes the work function
- If the flag is not set, the thread automatically locks the mutex and begins to wait for the signal of the condition variable
The key feature here is the third one. Here, thegnu/linux system allows you to complete the process of unlocking the mutex and waiting for the conditional variable signal with an atomic operation without being inserted by another thread. this avoids the possibility of other threads modifying the flag variable and sending a signal to the condition variable during the detection of flags and wait condition variables in thread_function.
the mutex is of type pthread_mutex_t variables, similar to mutexes, are initialized with two different methods:
One is static initialization, assigning a value to a lock variable Pthread_cond_initializer ,
pthread_cond_t cond = Pthread_cond_initializer;
a dynamic initialization, using a functionPthread_cond_init,
int Pthread_cond_init (pthread_cond_t *restrict cond,
Where the first parameter is a pointer to the pthread_cond_t variable. The second parameter is a pointer to the Property object of the condition variable, which is ignored in the Gnu/linux system.
The function pthread_cond_wait () causes the thread to block on a condition variable. The function prototypes are as follows:
#include <pthread.h> int pthread_cond_wait (pthread_cond_t *restrict cond, pthread_mutex_t *restrict Mutex);
The first parameter is a pointer to a pthread_cond_t type variable, and the second argument is a pointer to a pthread_mutex_t type variable. when calling Pthread_cond_wait, the mutex object must have been locked by the calling thread. This function unlocks the mutex with an atomic operation and locks the conditional variable to wait for the signal. When the signal arrives and the calling thread is unlocked, Pthread_cond_wait automatically requests the lock mutex object.
function The parameter mutex passed in to protect the condition, because when we call pthread_cond_wait, If the condition does not hold, we enter the block, but when the condition variable changes, we miss the condition. Because this thread has not yet been placed on the waiting queue, the mutex must be locked before calling Pthread_cond_wait, that is, calling Pthread_mutex_lock (), pthread_cond_wait after putting the thread in the blocking queue, Automatically unlocks the mutex,
The function pthread_cond_signal () is used to release a thread that is blocked on the condition variable cond. When multiple threads block on this condition variable, which thread is awakened is determined by the thread's scheduling policy. It is important to note that this function must be protected with a mutex that protects the condition variable, otherwise the condition satisfies the signal and may be emitted between the test condition and the call pthread_cond_wait function, resulting in an unrestricted wait. The function prototypes are as follows:
#include <pthread.h> int pthread_cond_signal (pthread_cond_t *cond);
An example is given below:
#include <stdio.h> #include <pthread.h> #include <unistd.h>int gval = 0;pthread_mutex_t Mutex = Pthread _mutex_initializer;pthread_cond_t cond = Pthread_cond_initializer;void *func1_th (void *arg) {Pthread_mutex_lock ( &mutex); if (5! = gval) {printf ("=======%s->%d===thread 1 wait start!====\n", __func__, __line__); Pthread_cond_wait (&cond, &mutex); When the condition is not satisfied, thread 1 automatically unlocks the mutex, allowing other threads to gain lock-in rights, and when the wake is received, the lock operation is performed}/** * do something here/printf ("=======% S->%d====thread 1 Do something!===\n ", __func__, __line__); Pthread_mutex_unlock (&mutex); return NULL;} void *func2_th (void *arg) {int i; Pthread_mutex_lock (&mutex); for (i = 0; i < i++) {printf ("=======%s->%d=======\n", __func__, __line__); Sleep (1); gval++; if (5 = = Gval) {pthread_cond_signal (&cond);//When the condition is met, thread 2 sends a signal and thread 1 receives a signal that is unblocked. printf ("=======%s->%d===signal====\n", __func__, __line__); } pthread_mutex_unlock (&mutex); } return NULL; int main (int argc, const char *argv[]) {pthread_t tid1, Tid2; if (0! = pthread_create (&TID1, NULL, func1_th, NULL)) {printf ("pthread_create failed!\n"); return-1; } sleep (1); Let thread 1 Execute first, enter the wait state if (0! = pthread_create (&tid2, NULL, func2_th, NULL)) {printf ("pthread_create failed!\n"); return-1; } pthread_join (Tid1, NULL); Pthread_join (Tid2, NULL); return 0;}
Another function to block a thread is pthread_cond_timedwait (). The function prototypes are as follows:
#include <pthread.h> int pthread_cond_timedwait (pthread_cond_t *restrict cond,
Like Pthread_cond_timedwait and Pthread_cond_wait, the mutex and wait condition variables are automatically unlocked, but it also limits the wait time. If the cond does not fire within the time specified by Abstime, the mutex mutex is re-locked and an error etimedout is returned.
. the function pthread_cond_broadcast (pthread_cond_t *cond) is used to wake up all threads that are blocked on the condition variable cond. These threads are awakened and will compete for the corresponding mutex again, so you must use this function with care. The function prototypes are as follows:
#include <pthread.h> int pthread_cond_broadcast (pthread_cond_t *cond);
Download the source code in this section:
Click to open link
Linux Mutex and synchronization application (ii): POSIX thread synchronization