Mutex lock mechanismMutual Exclusion (mutex) is a mechanism used in multi-threaded programming to prevent two threads from simultaneously reading and writing the same public resources (such as global variables. ToCodeSlice into one critical area (critical section. A Critical Zone refers to a piece of code for accessing public resources. It is not a mechanism orAlgorithm
Initialization:In Linux, the thread mutex data type is pthread_mutex_t. before use, initialize it: for the mutex of static allocation, you can set it to pthread_mutex_initializer, or call pthread_mutex_init. for the dynamically allocated mutex, after applying for memory (malloc), initialize with pthread_mutex_init and call pthread_mutex_destroy before releasing the memory (free.
Prototype:Int pthread_mutex_init (pthread_mutex_t * restrict mutex, const pthread_mutexattr_t * restric ATTR );
Return Value: 0 is returned for success, and error number is returned for error.
Note: If you use the default attribute to initialize mutex, you only need to set ATTR to null.
Mutex operation: To access shared resources, You need to lock the mutex. If the mutex has been locked, the calling thread will be blocked until the mutex is unlocked. after accessing the shared resources, unlock the mutex.
Lock and unlock function prototype:
# Include <pthread. h>
Int
Pthread_mutex_lock (pthread_mutex_t * mutex );
Int
Pthread_mutex_trylock (pthread_mutex_t * mutex );
Int pthread_mutex_unlock (pthread_mutex_t * mutex );
Return Value: 0 is returned for success, and error number is returned for error.
Description: The trylock function is a non-blocking call mode. That is, if the mutex is not locked, the trylock function locks the mutex, and get access to the shared resources. If the mutex is locked, the trylock function will not block the wait and return ebusy directly, indicating that the shared resources are busy.
Test instances to learn more about mutex
# Include <stdio. h>
# Include <stdlib. h>
# Include <unistd. h>
# Include <pthread. h>
# Include <errno. h>
Pthread_mutex_t mutex = pthread_mutex_initializer;
Int Lock_var;
Time_t end_time;
Void Pthread1 (Void * Arg );
Void Pthread2 ( Void * Arg );
Int Main ( Int Argc, Char * Argv [])
{
Pthread_t id1, Id2;
Pthread_t mon_th_id;
Int RET;
End_time = Time (null) + 10 ;
/* Mutex lock Initialization */
Pthread_mutex_init (& mutex, null );
/* Create two threads */
Ret = pthread_create (& id1, null ,( Void *) Pthread1, null );
If (Ret! = 0 )
Perror ( " Pthread cread1 " );
Ret = pthread_create (& Id2, null ,( Void *) Pthread2, null );
If (Ret! = 0 )
Perror ( " Pthread cread2 " );
Pthread_join (id1, null );
Pthread_join (Id2, null );
Exit ( 0 );
}
Void Pthread1 ( Void * Arg)
{
Int I;
While (Time (null) <end_time ){
/* Mutex lock */
If (Pthread_mutex_lock (& mutex )! = 0 ){
Perror ( " Pthread_mutex_lock " );
}
Else
Printf ( " Pthread1: pthread1 lock the variable \ n " );
For (I = 0 ; I < 2 ; I ++ ){
Sleep ( 1 );
Lock_var ++;
}
/* Mutex lock */
If (Pthread_mutex_unlock (& mutex )! = 0 ){
Perror ( " Pthread_mutex_unlock " );
}
Else
Printf ( " Pthread1: pthread1 unlock the variable \ n " );
Sleep ( 1 );
}
}
Void Pthread2 ( Void * Arg)
{
Int Nolock = 0 ;
Int RET;
While (Time (null) <end_time ){
/* Test mutex lock */
Ret = pthread_mutex_trylock (& mutex );
If (Ret = ebusy)
Printf ( " Pthread2: the variable is locked by pthread1 \ n " );
Else {
If (Ret! = 0 ){
Perror ( " Pthread_mutex_trylock " );
Exit ( 1 );
}
Else
Printf ( " Pthread2: pthread2 got lock. The variable is % d \ n " , Lock_var );
/* Mutex lock */
If (Pthread_mutex_unlock (& mutex )! = 0 ){
Perror ( " Pthread_mutex_unlock " );
}
Else
Printf ( " Pthread2: pthread2 unlock the variable \ n " );
}
Sleep ( 3 );
}
}
Zhaoxj $./thread_mutex
Pthread1: pthread1 Lock The variable
Pthread2: The variable Is Locked by pthread1
Pthread1: pthread1 unlock the variable
Pthread2: pthread2 got Lock . The variable Is 2
Pthread2: pthread2 unlock the variable
Pthread1: pthread1 Lock The variable
Pthread1: pthread1 unlock the variable
Pthread2: pthread2 got Lock . The variable Is 4
Pthread2: pthread2 unlock the variable
Pthread1: pthread1 Lock The variable
Pthread1: pthread1 unlock the variable
Pthread2: pthread2 got Lock . The variable Is 6
Pthread2: pthread2 unlock the variable
Pthread1: pthread1 Lock The variable
Pthread1: pthread1 unlock the variable
(Implement atomic operations for a piece of code) Description: Mutex semaphores do not lock a variable, but block a period.Program. If a mutex variable After the first execution of pthread_mutex_lock (mutex), during the period before unlock (mutex, If other threads run pthread_mutex_lock (mutex), the thread will be blocked, It cannot be executed until the previous thread is unlocked. Thus, synchronization can protect resources in the critical section.
Condition variable A condition variable is a mechanism for synchronizing global variables shared by threads. It mainly includes two actions: one thread waits for the condition variable to be established and suspends; Another thread sets "condition to true" (a signal indicating condition to true ). To prevent competition, the use of condition variables is always combined with a mutex lock.
Create and log out
1) Like the mutex lock, conditional variables have two creation methods: Static and Dynamic. The static method uses the pthread_cond_initializer constant: pthread_cond_t cond = pthread_cond_initializer; the dynamic method calls the pthread_cond_init () function: int pthread_cond_init (pthread_cond_t * cond, pthread_condattr_t * cond_attr)
2) to deregister a condition variable, you must call pthread_cond_destroy (). This condition variable can be deregistered only when no thread is waiting for the condition variable. Otherwise, ebusy is returned. Because the condition variables implemented in Linux do not allocate any resources, the logout action only includes checking whether there are waiting threads.Int pthread_cond_destroy (pthread_cond_t * Cond)
Waiting and stimulating:
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)
There are two waiting conditions: pthread_cond_wait () and pthread_cond_timedwait (). If the waiting time is not met before the given time, etimeout is returned and the waiting time ends, here, abstime appears in the absolute time format of the same meaning as the time () system call. 0 indicates GMT 00:00:00, January 1, January 1, 1970.
Either way, you must work with a mutex lock to prevent multiple threads from simultaneously requesting the Race Condition of pthread_cond_wait () (or pthread_cond_timedwait (), the same below ). Before calling pthread_cond_wait (), it must be locked by this thread (pthread_mutex_lock (), and mutex will be unlocked when the thread is suspended and waiting; before pthread_cond_wait () is met, mutex will be re-locked to match the lock action before entering pthread_cond_wait.It can be summarized as: the lock to be displayed by the thread before calling pthread_cond_wait (), and the unlock to be displayed by the thread after pthread_cond_wait. When pthread_cond_wait () is called, it implicitly locks and locks the mutex of this thread..
There are two types of excitation conditions: pthread_cond_signal () activates a thread waiting for this condition. When there are multiple waiting threads, one of them is activated in the queue order; and pthread_cond_broadcast () activate all the waiting threads. If the two do not have a waiting thread, nothing will be done.When pthread_cond_t calls pthread_cond_wait to enter the waiting state, the pthread_mutex_t mutex signal is invalid.Sample Code
1 # Include <stdio. h>
2 # Include <pthread. h> // Header files for Multithreading
3 # Include <semaphore. h> // Semaphores use header files
4
5 Pthread_cond_t g_cond; // Declare the lock and initialize it with a macro.
6 Pthread_mutex_t g_mutex;
7
8 Void Threadfun1 ( Void )
9 {
10 Int I;
11 Pthread_mutex_lock (& g_mutex ); // 1
12 Pthread_cond_wait (& g_cond, & g_mutex ); // If g_cond has no signal, it is blocked.
13
14 For (I = 0 ; I < 2 ; I ++ ){
15 Printf ( " Thread threadfun1. \ n " );
16 Sleep ( 1 );
17 }
18
19 Pthread_cond_signal (& g_cond );
20 Pthread_mutex_unlock (& g_mutex );
21 }
22
23 Int Main ( Void )
24 {
25 Pthread_t id1; // Thread identifier
26 Pthread_t Id2;
27
28 Pthread_cond_init (& g_cond, null ); // It can also be initialized in the program.
29 Pthread_mutex_init (& g_mutex, null ); // Mutex variable Initialization
30
31 Int I, RET;
32 Ret = pthread_create (& id1, null ,( Void *) Threadfun1, null );
33
34 If (Ret! = 0 ){ // If the value is not 0, the thread creation fails.
35 Printf ( " Create pthread1 error! \ N " );
36 Exit (1 );
37 }
38
39 Sleep ( 5 ); // Wait for the sub-thread to start first
40 Pthread_mutex_lock (& g_mutex ); // 2
41 Pthread_cond_signal (& g_cond ); // Give a start signal. Note that you must wait for the sub-thread to enter the waiting state before sending a signal. Otherwise, the signal is invalid.
42 Sleep ( 5 ); // At the moment, the sub-thread is still waiting, that is, the sub-thread is not scheduled.
43 Pthread_mutex_unlock (& g_mutex ); // Threadfun1 starts execution after unlocking
44
45 Pthread_join (id1, null );
46 Pthread_cond_destroy (& g_cond ); // Release
47 Pthread_mutex_destroy (& g_mutex ); // Release
48
49 Return 0 ;
50 }
See red colors 1 and 2,It is clear that 1 locks the mutex variable first, but the code can still be locked when it is executed to 2. Why?
Explanation:When the program enters pthread_cond_wait wait, g_mutex will be unlocked. When pthread_cond_wait is left, g_mutex will lock again. So g_mutex in main will be locked.