linux--linux mutexes, condition variables, and semaphores
for multithreaded programming, the most important thing to note is the shared data, because there is no way to know which thread will operate on it, or which thread will run first and which thread will run later. Therefore, these resources should be reasonable allocation and correct use. Under Linux, a mutex, condition variable, and semaphore are provided to protect the shared resource.
one, mutual exclusion lock
A mutex is a semaphore that is often used to prevent two processes or threads from accessing the same shared resource at the same time.
Required header file: Pthread.h Mutex identifier: pthread_mutex_t
(1) Mutual exclusion lock initialization:
function prototype: int pthread_mutex_init (pthread_mutex_t* mutex,const pthread_mutexattr_t* mutexattr);
function passed in value: Mutex: Mutex.
Mutexattr:pthread_mutex_initializer Create a quick mutex. PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP create a recursive mutex. PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP creates a fault-checking mutex. function return value: Success: 0; Error: -1
(2) Mutex operation function
int Pthread_mutex_lock (pthread_mutex_t* mutex);//Lock
int Pthread_mutex_trylock (pthread_mutex_t* mutex); Block only if the mutex is locked
int Pthread_mutex_unlock (pthread_mutex_t* mutex); Unlock
int Pthread_mutex_destroy (pthread_mutex_t* mutex); Purge Mutex function incoming value: Mutex: Mutex.
function return value: Success: 0; Error: 1
form of Use:
pthread_mutex_t Mutex;
Pthread_mutex_init (&mutex, NULL);/* define */...
Pthread_mutex_lock (&mutex);/* Get Mutex/*/* Critical resource */
Pthread_mutex_unlock (&mutex);/* Release Mutex */
if a thread has locked a mutex and then invokes the locked operation again during the operation, the thread will block indefinitely in this place, causing a deadlock. This requires a property of the mutex.
The mutex is divided into the following three types:
1, fast type. This type is also the default type. The behavior of the thread is as stated above.
2, recursive type. If we encounter the above mentioned deadlock situation, the same thread loop to lock the mutex, then the system will know that the lock behavior from the same thread, then will agree to the thread to lock the mutex.
3, error detection type. If the mutex is already locked, subsequent locks will fail without blocking, and the Pthread_mutex_lock () operation will return EDEADLK.
The property type of the mutex is pthread_mutexattr_t. After the declaration, call Pthread_mutexattr_init () to create the mutex. Then call Pthread_mutexattr_settype to set the property.
The format is as follows: int Pthread_mutexattr_settype (pthread_mutexattr_t *attr, int kind);
The first parameter, attr, is the property variable declared earlier, and the second parameter kind is the type of property we want to set. He has several options:
Pthread_mutex_fast_np
Pthread_mutex_recursive_np
Pthread_mutex_errorcheck_np
Here's a simple procedure for using properties:
pthread_mutex_t Mutex;
pthread_mutexattr_t attire;
Pthread_mutexattr_init (&ATTR);
Pthread_mutexattr_settype (&ATTR,PTHREAD_MUTEX_RECURSIVE_NP);
Pthread_mutex_init (&MUTEX,&ATTR);
Pthread_mutex_destroy (&ATTR);
we mentioned earlier that when calling Pthread_mutex_lock (), if the mutex is locked by another thread at this point, the operation will always be blocked in this place. If we do not want to block this place at this time, then we can call the following function: Pthread_mutex_trylock.
If the mutex is not locked at this time, then Pthread_mutex_trylock will return 0, and the mutex will be locked. If the mutex is already locked, it will return to Ebusy immediately.
Second, the condition variable
Required Header files: pthread.h
Condition variable identifier: pthread_cond_t
1, the existence of mutual exclusion lock problem:
One obvious disadvantage of mutexes is that it has only two states: locking and non-locking. Imagine a simple scenario: When multiple threads access the same shared resource, they do not know when the shared resource should be used, if a judgment statement is added to the critical section, or it can be effective, but one is inefficient, and the complex environment is difficult to write, we need a structure that can trigger the corresponding thread when the condition is set. Make variable modifications and access.
2. Condition variables:
Conditional variables compensate for the lack of mutexes by allowing threads to block and wait for another thread to send a signal, which is often used in conjunction with mutexes. When used, a condition variable is used to block a thread, and when the condition is not met, the thread often unlocks the corresponding mutex and waits for the condition to change. Once another thread changes the condition variable, it notifies the corresponding condition variable to wake one or more threads that are being blocked by this condition variable. These threads will re-lock the mutex and re-test whether the condition is satisfied.
3. Correlation function of condition variable
pthread_cond_t cond = Pthread_cond_initializer; Conditional variable Structure
int Pthread_cond_init (pthread_cond_t *cond, pthread_condattr_t*cond_attr);
int pthread_cond_signal (pthread_cond_t *cond);
int Pthread_cond_broadcast (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_destroy (pthread_cond_t *cond);
Detailed Description:
(1) Create and unregister
Conditional variables, like mutexes, have both static and dynamic methods of creation.
A. Static mode
Use the Pthread_cond_initializer constant in static mode, as follows: pthread_cond_t Cond=pthread_cond_initializer
B. Dynamic approach
The Pthread_cond_init () function is called dynamically, and the API is defined as follows:
int Pthread_cond_init (pthread_cond_t *cond, pthread_condattr_t *cond_attr)
Although the POSIX standard defines attributes for a condition variable, it is not implemented in Linuxthreads, so the cond_attr value is usually null and is ignored.
Unregistering a condition variable calls Pthread_cond_destroy () to unregister the condition variable only if no thread is waiting on the condition variable, otherwise it returns EBUSY. Because the condition variables implemented by Linux do not have any resources assigned to them, the logoff action includes checking for waiting threads only.
The API is defined as follows: int Pthread_cond_destroy (pthread_cond_t *cond)
(2) Waiting and excitation
A. Waiting
int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)//wait
int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, const struct TIMESPEC *abstime)//sometimes wait
There are two ways of waiting: unconditionally Waiting for pthread_cond_wait () and timing waiting for pthread_cond_timedwait (), where the timing wait method returns Etimeout, ends the wait, if the condition is not met before the given moment. Where abstime occurs in an absolute time form that is the same as when the system call is made, 0 means January 1, 1970 0:0 0 seconds GMT. Regardless of the wait mode, you must mate with a mutex to prevent multiple threads from simultaneously requesting a race condition (Race Condition) for pthread_cond_wait () (or pthread_cond_timedwait (), hereinafter). The mutex mutex must be a normal lock (PTHREAD_MUTEX_TIMED_NP) or an adaptive lock (PTHREAD_MUTEX_ADAPTIVE_NP), and the call to Pthread_cond_wait () Before the update condition waits for the queue, the mutex remains locked and unlocked before the thread hangs into the wait before it must be Cheng (Pthread_mutex_lock ()) by this line. Before the condition satisfies thereby leaving pthread_cond_wait (), the mutex will be re-locked to correspond to the lock action before entering Pthread_cond_wait ().
B. Inspire
There are two forms of the excitation condition, pthread_cond_signal () activates a thread waiting for the condition, and when there are multiple waiting threads, one is activated in the queued order;
The Pthread_cond_broadcast () activates all waiting threads.
(3) Other operations
Both pthread_cond_wait () and pthread_cond_timedwait () are implemented as cancellation points, so the threads waiting at that point will rerun immediately, leaving Pthread_cond_wait () after the mutex is re-locked, Then perform the cancel action. That is, if Pthread_cond_wait () is canceled, the mutex remains locked, so you need to define an exit callback function to unlock it. Pthread_cond_wait can actually be seen as a combination of the following actions: Unlock the thread lock, the wait condition is true;
form of Use:
Thread One code
pthread_mutex_lock (&mutex), if (condition satisfied)
Pthread_cond_signal (&cond); Pthread_mutex_unlock (&mutex);
//Thread two code
Pthread_mutex_lock (&mutex), while (condition not satisfied)
Pthread_cond_wait (&cond, &mutex); Pthread_mutex_unlock (&mutex);
/* Why use while in thread two? Since there is a time difference between the return of Pthread_cond_signal and pthread_cond_wait, it is assumed that the conditions have changed in this difference, and it is clear that the condition needs to be re-examined. This means that the condition may not have been established when the pthread_cond_wait is awakened. */
Three, the semaphore
The semaphore is actually a counter and an integer. Each time the wait operation is called, the semaphore value is reduced by one, and if the semaphore value is already 0, the wait operation is blocked. Each time the post operation is called, the semaphore value is added one. Required header file: Semaphore.h semaphore identifier: sem_t
Main function: (1) sem_init
Function: used to create a semaphore, And initializes the value of the semaphore.
Function prototype: int sem_init (sem_t* sem, int pshared, unsigned int value), function passed in value: SEM: semaphore.
Pshared: Determines whether the semaphore can be shared between several processes. Since Linux has not yet realized the amount of information that is shared between processes, this value can only take 0. Value: initial calculator
function return value: 0: Success;-1: Failed.
(2) other functions. Wait for semaphore
int sem_wait (sem_t* sem);
int sem_trywait (sem_t* sem); Send Signal Volume
int sem_post (sem_t* sem);
Get the semaphore value
int Sem_getvalue (sem_t* sem); Delete semaphore
int Sem_destroy (sem_t* sem);
Functions: Sem_wait and sem_trywait are equivalent to P operations, they all can reduce the value of the semaphore by one, the difference is that if the value of the semaphore is less than zero, SEM_WAIT will block the process, and Sem_trywait will return immediately.
The sem_post is equivalent to a V operation, which adds a value to the semaphore and sends a wake-up signal to the waiting process (or thread). Sem_getvalue gets the value of the semaphore. Sem_destroy destroys the semaphore.
Use form: sem_t sem;
Sem_init (&sem, 0, 1); /* Semaphore initialization */...
Sem_wait (&sem); /* Wait for the semaphore */.../* Critical resource */
Sem_post (&sem); /* Release the semaphore */
The semaphore differs from the thread lock and condition variable in the following ways:
1) The lock must be the same thread to get and release, otherwise it will deadlock. The condition variables and semaphores do not have to be.
2) The increase and decrease of the signal will be automatically remembered by the system, there is a counter inside the system to achieve the semaphore, do not have to worry about loss, and wake up a condition variable, if there is no corresponding thread waiting for the condition variable, this wake will be lost.
Linux mutexes, condition variables, and semaphores