Linux thread Sync __linux

Source: Internet
Author: User
Tags mutex posix semaphore
A Mutual exclusion Lock
Although the mutex mutex function can also be implemented using the IPC semaphore mechanism in POSIX thread, it is clear that Semphore is too powerful to define another set of mutex functions specifically for thread synchronization in POSIX thread.

1. Create and destroy
There are two ways to create mutexes, both statically and dynamically. POSIX defines a macro pthread_mutex_initializer to statically initialize a mutex, as follows:
pthread_mutex_t Mutex=pthread_mutex_initializer;
In the Linuxthreads implementation, pthread_mutex_t is a struct, and pthread_mutex_initializer is a structural constant.

The dynamic approach is to initialize the mutex using the Pthread_mutex_init () function, which is defined as follows:
int Pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Where mutexattr is used to specify the mutex attribute (see below), and if NULL, the default is used.

Pthread_mutex_destroy () is used to unregister a mutex, and the API is defined as follows:
int Pthread_mutex_destroy (pthread_mutex_t *mutex)
Destroying a mutex means releasing the resources it occupies and requiring that the lock is currently open. Because mutexes do not occupy any resources in Linux, Pthread_mutex_destroy () in Linuxthreads has no other action except to check the lock state (the lock returns EBUSY).

2. Mutex properties
The properties of the mutex are specified when the lock is created, and there is only one lock type attribute in the Linuxthreads implementation, and different lock types behave differently when attempting to lock a mutex that has been locked. Currently (glibc2.2.3,linuxthreads0.9) has four values to choose from:

PTHREAD_MUTEX_TIMED_NP, this is the default value, which is the normal lock. When a line is Cheng, the rest of the thread requesting the lock forms a wait queue and gets the lock by priority after the unlock. This lock strategy ensures the fairness of resource allocation.
pthread_mutex_recursive_np, nested locks, allows the same thread to successfully obtain multiple times for the same lock and unlock it through multiple unlock. If it is a different thread request, it will be threads unlocked when the lock line is being added.
PTHREAD_MUTEX_ERRORCHECK_NP, check the wrong lock, if the same thread request the same lock, then return EDEADLK, otherwise the same as the PTHREAD_MUTEX_TIMED_NP type action. This ensures that the simplest case deadlock does not occur when multiple locks are not allowed.
PTHREAD_MUTEX_ADAPTIVE_NP, adapt to the lock, the simplest type of lock, only wait to unlock after the competition.

3. Lock operation
Lock operations mainly include lock Pthread_mutex_lock (), Unlock pthread_mutex_unlock () and Test lock Pthread_mutex_trylock () Three, no matter which type of lock, can not be two different threads at the same time , and must wait to unlock it. For ordinary locks and adaptive lock types, the unlocking can be any thread in the process; and the wrong lock must be unlocked by the lock to be effective, otherwise return eperm; for nested locks, document and implementation requirements must be unlocked by the lock, but the experimental results show that there is no such limitation, and this difference has not yet been explained. Threads in the same process, if unlocked after locking, no more locks can be acquired by any other thread.

int Pthread_mutex_lock (pthread_mutex_t *mutex)
int Pthread_mutex_unlock (pthread_mutex_t *mutex)
int Pthread_mutex_trylock (pthread_mutex_t *mutex)

The Pthread_mutex_trylock () semantics are similar to Pthread_mutex_lock (), but instead of suspending the wait when the lock is occupied, the Ebusy is returned.

4. Other
The Linux implementation of the POSIX thread lock mechanism is not a cancellation point, so a thread with a deferred cancellation type will not leave the lock wait for the cancellation signal. It is noteworthy that if the thread is canceled before the lock is unlocked, the lock remains locked forever, so if there is a cancellation point in the critical section or if an asynchronous cancellation type is set, you must unlock it in the exit callback function.

This lock mechanism is also not asynchronous signal security, that is, should not be used in the signal processing of mutual-exclusion locks, otherwise it is easy to cause deadlock.

Two Condition variable
A condition variable is a mechanism for synchronizing a global variable shared between threads, consisting mainly of two actions: one thread waits for the condition of the condition variable to hang, and the other thread makes the condition set (the conditional signal). To prevent competition, the use of conditional variables is always combined with a mutex.

1. Create and Log off
A conditional variable, like a mutex, has two ways to create static dynamics, using the Pthread_cond_initializer constant in static mode, as follows:
pthread_cond_t Cond=pthread_cond_initializer

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 a property for a condition variable but is not implemented in Linuxthreads, the cond_attr value is usually null and is ignored.

Logging off a condition variable requires a call to Pthread_cond_destroy (), which can be logged out only if no thread is waiting on the condition variable, otherwise the ebusy is returned. Because the condition variables of the Linux implementation do not allocate any resources, the logoff action only includes checking for a wait thread. The API is defined as follows:
int Pthread_cond_destroy (pthread_cond_t *cond)

2. Wait and inspire
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)

There are two ways to wait conditions: unconditionally wait for pthread_cond_wait () and wait pthread_cond_timedwait (), where the timing waits if the condition is not met at a given moment, then return to Etimeout and end the wait. where abstime in the same sense as the time () system calls the absolute times form, 0 GMT January 1, 1970 0:0 0 seconds.

Either way, you must work with a mutex to prevent multiple threads from simultaneously requesting pthread_cond_wait () (or pthread_cond_timedwait (), the same below) competition conditions (Race Condition). A mutex mutex must be a normal lock (PTHREAD_MUTEX_TIMED_NP) or an adaptive lock (PTHREAD_MUTEX_ADAPTIVE_NP) and be invoked pthread_cond_wait () The front must be Cheng by this line (Pthread_mutex_lock ()), and before the update condition waits for the queue, the mutex remains locked and the thread hangs into the wait before it unlocks. Before the condition is satisfied and leaves the pthread_cond_wait (), the mutex is locked back to correspond to the locking action before entering the pthread_cond_wait ().

There are two forms of excitation conditions, pthread_cond_signal () activates a thread waiting for the condition, one is activated in the queue while there are multiple waiting threads, and pthread_cond_broadcast () activates all waiting threads.

3. Other
Pthread_cond_wait () and pthread_cond_timedwait () are implemented as cancellation points, so the thread waiting at that place will be rerun immediately, leaving Pthread_cond_wait () after the mutex is locked. And then perform the cancel action. This means that if the pthread_cond_wait () is canceled, the mutex remains locked, and the exit callback function needs to be defined to unlock it.

The following example sets out the combination of mutexes and conditional variables, and the effect of cancellation on conditional wait actions. In the example, two threads are started and wait for the same condition variable, and if you do not use the exit callback function (see the annotation section in the example), Tid2 will wait forever at Pthread_mutex_lock (). If the callback function is used, the TID2 condition and the main thread's conditional excitation are working correctly.


#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

pthread_mutex_t Mutex;
pthread_cond_t cond;

void * Child1 (void *arg)
{
Pthread_cleanup_push (Pthread_mutex_unlock,&mutex); /* Comment 1 * *
while (1) {
printf ("Thread 1 get running \ n");
printf ("Thread 1 Pthread_mutex_lock returns%d\n",
Pthread_mutex_lock (&mutex));
Pthread_cond_wait (&cond,&mutex);
printf ("Thread 1 condition applied\n");
Pthread_mutex_unlock (&mutex);
Sleep (5);
}
Pthread_cleanup_pop (0); /* Comment 2 * *
}

void *child2 (void *arg)
{
while (1) {
Sleep (3); /* Comment 3 * *
printf ("Thread 2 Get running.\n");
printf ("Thread 2 Pthread_mutex_lock returns%d\n",
Pthread_mutex_lock (&mutex));
Pthread_cond_wait (&cond,&mutex);
printf ("Thread 2 condition applied\n");
Pthread_mutex_unlock (&mutex);
Sleep (1);
}
}

int main (void)
{
int Tid1,tid2;

printf ("Hello, condition variable test\n");
Pthread_mutex_init (&mutex,null);
Pthread_cond_init (&cond,null);
Pthread_create (&tid1,null,child1,null);
Pthread_create (&tid2,null,child2,null);
do{
Sleep (2); /* Comment 4 * *
Pthread_cancel (TID1); /* Comment 5 * *
Sleep (2); /* Comment 6 * *
Pthread_cond_signal (&cond);
}while (1);
Sleep (100);
Pthread_exit (0);
}



Without the Pthread_cancel () Action of comment 5, child1 and child2 will work even without those sleep () delay operations. The delay in note 3 and comment 4 allows the child1 to complete the cancellation action so that child2 can enter the request-lock operation after Child1 exits. If there are no callback function definitions for annotations 1 and 2, the system hangs where the Child2 requests the lock, and if the delay of annotation 3 and comment 4 is not done, the child2 can be controlled before the child1 completes the cancellation action, thereby successfully executing the request lock. However, it may be suspended in pthread_cond_wait () because there is also an operation to request a mutex. The Child1 function gives the use of standard condition variables: callback function protection, pending condition locking, pthread_cond_wait () back to unlock.

The conditional variable mechanism is not safe for asynchronous signals, that is, calling pthread_cond_signal () or Pthread_cond_broadcast () in a signal processing function is likely to cause a deadlock.

Three Lights
The main difference between a semaphore and a mutex and a condition variable lies in the concept of "light", which means that resources are available and lights are not. If the latter two are synchronized in a way that focuses on the "wait" operation, that is, when resources are not available, the signal mechanism focuses on lighting, that is, to inform the resources available; It is meaningless not to wait for the thread to unlock or excite the condition, but the light operation of the thread without waiting for the light is valid and can keep the lights on. Of course, such an operating primitive also means more overhead.

The application of signal lights in addition to light/light out of this binary lamp, can also be more than 1 of the number of lights to indicate that the number of resources is greater than 1, at this time can be called multiple lights.

1. Create and Log off
POSIX signal standard defines the name of the signal and the unknown signal lights, but the realization of the linuxthreads only nameless lights, at the same time the famous lamp can always be used in addition to the many processes, in the use of the nameless lights and not very different, so the following only on the nameless lights for discussion.

int Sem_init (sem_t *sem, int pshared, unsigned int value)
This is the API for creating the semaphore, where value is the initial value of the semaphore, and pshared represents whether it is shared for multiple processes and not just for a process. Linuxthreads does not implement a multiple-process shared semaphore, so all pshared inputs that are not 0-valued will return Sem_init () to 1, and the errno to Enosys. The initialized signal lamp is characterized by SEM variable, and is used for the following operation of lighting and quenching.

int Sem_destroy (SEM_T * sem)
The cancellation of the signal light SEM requires no thread to wait for the signal, or return-1, and set errno as Ebusy. In addition, the Linuxthreads Semaphore logoff function does not do other actions.

2. Lighting and lights
int sem_post (SEM_T * sem)
The lighting operation adds 1 to the semaphore value, indicating an additional accessible resource.

int sem_wait (SEM_T * sem)
int sem_trywait (SEM_T * sem)
Sem_wait () waits for the light operation, waits for the light to light (the semaphore value is greater than 0), and then the signal atom is reduced by 1, and returns. Sem_trywait () is a non-blocking version of Sem_wait (), if the semaphore count is greater than 0, then the atom is reduced by 1 and returns 0, otherwise the -1,errno is immediately returned to Eagain.

3. Get Light value
int Sem_getvalue (SEM_T * sem, int * sval)
Read the light count in the SEM, save in the *sval, and return 0.

4. Other
Sem_wait () is implemented as a cancellation point, and in an architecture that supports atomic "compare and swap" instructions, sem_post () is the only one that can be used for asynchronous signal processing functions for POSIX asynchronous signal security APIs.

Four Asynchronous signal
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.