I. Introduction
1.1 process/Thread Synchronization Method
Common process/Thread Synchronization Methods include Mutex, rdlock, cond, and Semophore.
In windows, the Critical Section and Event are also common Synchronization Methods.
1.2 recursive lock/non-recursive lock
Mutex can be divided into recursive mutex and non-recursive mutex ). Recursive locks are also called reentrant mutex. non-recursive locks are also called non-reentrant mutex ).
UniqueDifferencesYes:
The same thread can obtain the same recursive lock Multiple times without deadlock.
If a thread acquires the same non-recursive lock multiple times, a deadlock occurs.
The Mutex and Critical sections in Windows are recursive.
The pthread_mutex_t lock in Linux is non-recursive by default. You can set the PTHREAD_MUTEX_RECURSIVE attribute to set the pthread_mutex_t lock to a recursive lock.
Ii. Code
2.1 Critical Section recursive lock
[Cpp]View plaincopy
- # Include # Include
- # Include
- Int counter = 0;
- CRITICAL_SECTION g_cs;
- Void doit (void * arg ){
- Int I, val; for (I = 0; I <5000; I ++)
- {EnterCriticalSection (& g_cs );
- EnterCriticalSection (& g_cs );
- Val = counter; printf ("thread % d: % d \ n", int (arg), val + 1 );
- Counter = val + 1;
- LeaveCriticalSection (& g_cs );
- }}
- Int main (int argc, char * argv [])
- {InitializeCriticalSection (& g_cs );
- HANDLE hThread1 = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) doit, (void *) 1, 0, NULL );
- HANDLE hTrehad2 = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) doit, (void *) 2, 0, NULL );
- WaitForSingleObject (hThread1, INFINITE); WaitForSingleObject (hTrehad2, INFINITE );
- DeleteCriticalSection (& g_cs );
-
- Return 0 ;}
Result: The values of 1-2 locks and 1-2 locks can be correctly output ~ 10000.2.2 pthread_mutex_t non-recursive lock
[Cpp]View plaincopy
- # Include # Include
- # Include
- Int counter = 0;
- Pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
- Void * doit (void *){
- Int I, val; for (I = 0; I <5000; I ++)
- {Pthread_mutex_lock (& g_mutex );
- Pthread_mutex_lock (& g_mutex );
- Val = counter; printf ("% x: % d \ n", pthread_self (), val + 1 );
- Counter = val + 1;
- Pthread_mutex_unlock (& g_mutex );
- }}
- Int main (int argc, char * argv [])
- {Pthread_t tid1, tid2;
- Pthread_create (& tid1, NULL, doit, NULL );
- Pthread_create (& tid2, NULL, doit, NULL );
- Pthread_join (tid1, NULL); pthread_join (tid2, NULL );
- Return 0;
- }
Result: After the lock is applied, the result is correct ~ 10000; add two locks, deadlock, no output information.
2.3 pthread_mutex_t recursive lock (PTHREAD_MUTEX_RECURSIVE)
[Cpp]View plaincopy
- # Include # Include
- # Include
- Int counter = 0;
- Pthread_mutex_t g_mutex; // = PTHREAD_MUTEX_INITIALIZER;
- Void * doit (void *){
- Int I, val; for (I = 0; I <5000; I ++)
- {Pthread_mutex_lock (& g_mutex );
- Pthread_mutex_lock (& g_mutex );
- Val = counter; printf ("% x: % d \ n", pthread_self (), val + 1 );
- Counter = val + 1;
- Pthread_mutex_unlock (& g_mutex );
- }}
- Int main (int argc, char * argv [])
- {// Create recursive attribute
- Pthread_mutexattr_t attr; pthread_mutexattr_init (& attr );
- // Set recursive attribute
- Pthread_mutexattr_settype (& attr, PTHREAD_MUTEX_RECURSIVE );
- Pthread_mutex_init (& g_mutex, & attr );
- Pthread_t tid1, tid2;
- Pthread_create (& tid1, NULL, doit, NULL); pthread_create (& tid2, NULL, doit, NULL );
- Pthread_join (tid1, NULL );
- Pthread_join (tid2, NULL );
- Pthread_mutex_destroy (& g_mutex );
- // Destroy recursive attribute
- Pthread_mutexattr_destroy (& attr );
- Return 0 ;}
Result: The values of 1-2 locks and 1-2 locks can be correctly output ~ 10000. ,
In thread synchronization, using locks is a very common practice. Try to use non-recursive locks to avoid using recursive locks!
The logic of non-recursive locks is clear and can be easily debugged when a deadlock occurs! You only need to use non-recursive locks with one click!