Conditional variables, semaphores, and mutex locks

Source: Internet
Author: User
Tags semaphore

Reproduced http://blog.csdn.net/yusiguyuan/article/details/14161225

 

The synchronization technology between threads mainly focuses on mutex locks and condition variables. The combination of condition variables and mutex can well handle the synchronization problem between threads waiting for conditions. For example, if there are two variables X, Y needs to synchronize among multiple threads and start different thread execution sequence based on the size comparison between them, this uses the conditional variable technique. View code

 1 #include <iostream> 2 #include <pthread.h> 3 using namespace std; 4  5 pthread_cond_t qready = PTHREAD_COND_INITIALIZER; 6 pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER; 7 pthread_t tid1,tid2,tid3; 8  9 int x = 10;10 int y = 20;11 12 13 void *thrd_1(void *arg)14 {15     pthread_mutex_lock(&qlock);16     while(x<y)17     {18         pthread_cond_wait(&qready,&qlock);19     }20     pthread_mutex_unlock(&qlock);21     cout<<"1"<<endl;22     sleep(5);23 }24 25 void *thrd_2(void *arg)26 {27     pthread_mutex_lock(&qlock);28     x = 20;29     y = 10;30     cout<<"has change x and y"<<endl;31 32     pthread_mutex_unlock(&qlock);33     if(x > y)34     {35         pthread_cond_signal(&qready);36     }37     cout<<"2"<<endl;38 }39 40 void *thrd_3(void *arg)41 {42     pthread_join(tid1,NULL);43     cout<<"3"<<endl;44 }45 46 int main(int argc,char **argv)47 {48     int err;49     err = pthread_create(&tid1,NULL,thrd_1,NULL);50     if(err != 0)51     {52         cout<<"pthread 1 create error"<<endl;53     }54     err = pthread_create(&tid2,NULL,thrd_2,NULL);55     if(err != 0)56     {57         cout<<"pthread 2 create error"<<endl;58     }59     err = pthread_create(&tid3,NULL,thrd_3,NULL);60     if(err != 0)61     {62         cout<<"pthread 3 create error"<<endl;63     }64     while(1)65     {66         sleep(1);67     }68     return 0;69 70 }

We can see that after three threads are created, the execution sequence is 2, 1, 3, that is, the number printed is 213. Why is this order? Next let's take a look. When the tid1 thread is created, it enters the thread function, adds a lock, and then enters the pthread_cond_wait function. This function is used to wait for the qready condition variable to succeed, what is this condition? As we will see later, we only need to know that this function will be stuck here when the qready condition is not met, and will unlock the mutex lock passed in. Why should we unlock it, think about it. If you don't unlock it, there will be no external permission to modify X and Y. If you want to modify these two values for the other two threads, You need to lock qclock.

After thread 1 is ready, thread 2 will be run. Let's look at the thread function of thread 2. The function is also locked at the beginning, but when pthread_cond_wait of thread 1 is unlocked, it can continue to run, and, after that, it modifies X and Y, unlocks it after modification, and CALLS pthread_cond_signal to notify thread 1, now you can understand it. The condition is x> Y. Now there is a problem. Do you have to unlock it before sending the notification? The answer is yes. Why, because if pthread_cond_wait returns a notification signal to thread 1 before thread 2 is unlocked, will lock the lock again, and this has not been unlocked in thread 2, it will be stuck for the next time. Although this will be eliminated when thread 2 runs to the unlock location, it does not meet our sometimes needs, so it is best to send a signal after unlocking. (If you cannot understand it, you can refer to the section in red below !!!) So we can see why thread 2 is always executed before thread 1, let alone thread 3. You can understand pthread_join !!!  

 

 

To allow data sharing between threads or processes, synchronization is usually required. Common Synchronization Methods include mutex lock, condition variable, read/write lock, and semaphore. In addition, synchronization between processes can also be performed through inter-process communication, including pipelines (unknown pipelines and famous pipelines), semaphores, message queues, shared memory, and remote process calls can also be controlled over the network through sockets.

I. mutex lock and condition variable are the basic components of synchronization.

Mutex locks and condition variables come from the posix.1 thread standards and are used by various threads in the same process in the same step. However, if the two are stored in the memory zone shared by multiple processes, they can also be used for inter-process synchronization.

1. mutex lock is used to protect the critical section, so that only one thread can execute the code at any time. Its outline is roughly as follows:

Lock_the_mutex (...);

Critical Section

Unlock_the_mutex (...);

The following three functions lock and unlock a mutex lock:

# Include <pthread. h>

Int pthread_mutex_lock (pthread_mutex_t * mptr); // If the lock cannot be obtained immediately, it will be blocked here

Int pthread_mutex_trylock (pthread_mutex_t * mptr); // If the lock cannot be obtained immediately, ebusy is returned. You can perform other operations based on the returned value in non-blocking mode.

Int pthread_mutex_unlock (pthread_mutex_t * mptr); // release the lock

Mutex lock is usually used to protect the shared data shared by multiple threads or processes)

2. Condition variable, which is a sending and waiting signal. The user locks the mutex lock, and the condition variable is used for waiting. In general, calling pthread_cond_wait (...) in a process/thread (..) wait for a condition to be established. At this time, the process is blocked. Another process/thread performs some operation. When a condition is set, pthread_cond_signal (...) is called (...) so that pthread_cond_wait (...). It should be noted that the signal mentioned here is not a system-level sigxxxx signal, but it is easier to understand with the word "signal. The condition variable is closer to the semaphore or can be considered as a semaphore.

The following two functions are used to control conditional variables:

# Include <pthread. h>

Int pthread_cond_wait (pthread_cond_t * cptr, pthread_mutex_t * mptr );

Int pthread_cond_signal (pthread_cond_t * cptr );

From the code, we can see that the use of condition variables requires a lock mechanism, that is, the mutex lock mentioned above. That is to say, a process/thread must wait until the shared data in the critical section reaches a certain state before performing some operation, and this state is true, then, a signal is sent to notify another process/thread.

In fact, the pthread_cond_wait function can also use a while endless loop to wait for the condition to be set up. However, it should be noted that using the while endless loop will seriously consume the CPU, pthread_cond_wait adopts the thread sleep mode, which is a waiting mode rather than a constant check mode.

In general, the code for sending signals to conditional variables is roughly as follows:

Pthread_mutex_lock (& mutex );

Set the condition to true

  

Pthread_mutex_unlock (& mutex );

Pthread_cond_signal (& Cond); // send a signal

The code for waiting condition and going to sleep to wait for the condition to become true is roughly as follows:

Pthread_mutex_lock (& mutex );

While (the condition is false)

Pthread_cond_wait (& cond, & mutex );

Execute an operation

Pthread_mutex_unlock (& mutex );

Note that pthread_cond_wait (& cond, & mutex) is an atomic operation. When it is executed, it first unlocks mutex, in this way, other threads can get the lock to modify the condition. After pthread_cond_wait is unlocked, the thread/process will be put into sleep. In addition, when the function returns, mutex will be locked again, in this way, the lock can be unlocked after an operation is executed.

 

Ii. read/write locks

As the name suggests, read/write locks are also a kind of lock. They are improved based on the mutex lock. When a process/thread obtains the write lock, other processes/Threads can still obtain the lock, only the read lock is obtained. Because a process/thread writes data, the read operations of other processes/threads are not affected.

 

3. semaphores

Semaphore is a primitive used to provide synchronization means between different processes or threads. You can understand it.

Process a process B

\/

Process \/

----------------------------------------------------

Kernel \/

Semaphores

That is to say, the semaphores are maintained by the kernel and are independent of processes. Therefore, you can use it for synchronization.

Generally, it is based on the famous POSIX semaphore and can be considered as a special file in the system (because everything in Linux can be considered as a file ), because many processes are used for communication and synchronization, if it is a synchronization between threads, it is often used based on POSIX memory semaphores. (The memory-based semaphores must be specified during creation to determine whether to share among processes. The famous semaphores must be manually deleted as the kernel persists, and the memory-based semaphores must be continuously deleted with the process)

The working principle of semaphores is similar to mutex lock + condition variable.

The main functions are sem_open, sem_close, and sem_unlink. Note that close only closes the semaphores but does not delete them from the system. Unlink deletes the semaphores.

The sem_wait and sem_trywait functions are similar to those of pthread_cond_wait. They both wait for the establishment of a condition. The difference between sem_wait and sem_trywait is that when the specified semaphore value is 0, the latter does not put the caller into sleep, but immediately returns eagain, that is, retry.

Sem_post and sem_getvalue functions. sem_post adds one of the specified semaphores, and then wakes up any thread waiting for the signal value to become a positive number. Sem_getvalue is a function used to obtain the current signal value.

 

Summary:

Differences among mutex lock, condition variable, and semaphore:

(1) The mutex lock must always be unlocked by the lock thread (because other threads cannot obtain the lock at this time). The semaphore does not have this restriction: A thread waits for a semaphore, another thread can mount the semaphore.

(2) Each semaphore has a value associated with it. When the output is + 1 and the wait time is-1, any thread can generate a signal, even if no thread is waiting for the semaphore value. However, for conditional variables, if no thread is blocked on pthread_cond_wait after pthread_cond_signal, the signal on this conditional variable is lost.

(3) among various synchronization techniques, the only function that can be safely called from the signal processing program is sem_post.

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.