Linux multithread synchronization ----- condition variable

Posted by AdamDowning on Tue, 07 Dec 2021 21:08:57 +0100

Let's first look at the description of condition variables in Linux high performance server programming:

The above words can be summarized as follows:

        Condition variables can be used when a thread in a multithread depends on the change of shared data by another thread!

It's easy to understand conditional variables with the of consumers and producers

  From: Basic concepts and principles of conditional variables_ Believe in and love your technology blog_ 51CTO blog_ Conditional variable_ Conditional variable principle

As the elder brother mentioned above, it can be seen very thoroughly from the perspective of consumers and producers. Wake up when needed and sleep when not needed.

Let's take a look at the functions and header files used by conditional variables:

#include <pthread.h>     // Header files are as like as two peas used for creating functions.

int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *attr);   // Initialization of condition variables

The first parameter is the pointer of the condition variable, and the second parameter is the attribute of the condition variable, which is generally set to NULL

  int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);// Wait until the condition variable is satisfied. After waking up, the thread will be started. Otherwise, the thread will always be blocked

The first parameter is a pointer to the condition variable, and the second parameter is a mutex (mutexes and condition variables are generally used together. Why? Because mutexes have only two states, locked and unlocked, while condition variables can send signals between threads to make threads wait or wake up, which makes up for the single locking mode of mutexes. Therefore, mutexes and condition variables are generally used together).

int pthread_cond_signal(pthread_cond_t *cond);      // Wake up a single thread

int pthread_cond_broadcast(pthread_cond_t *cond);  // Wake up all waiting threads

int pthread_cond_destroy(pthread_cond_t *cond);     // Destruction of conditional variables

The parameters of the above three functions are pointers to conditional variables

Let's take a look at a piece of code. Its function is that the main thread writes data to the buff. In the process of writing, two sub threads are waiting. After the main thread writes, the sub thread completes printing. Then, when the main thread inputs end, the process ends!

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

pthread_mutex_t mutex;  //Create mutex
pthread_cond_t cond;    //Create condition variable
 
char buff[128] = {0}; 

void* funa(void* arg)
{
    while( 1 )
    {
    //Waiting conditions available
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&cond,&mutex);
        pthread_mutex_unlock(&mutex);

        if ( strncmp(buff,"end",3) == 0 )
        {
            break;
        }
    //Print buff
        printf("funa buff=%s\n",buff);
    }
}

void * funb(void* arg)
{
    while( 1 )
    {
    //Waiting conditions available
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&cond,&mutex);  //Wait for the signal from the main thread after locking the mutex
        pthread_mutex_unlock(&mutex);

        if ( strncmp(buff,"end",3) == 0 )
        {
            break;
        }
    //Print buff
        printf("funb buff=%s\n",buff);
    }

}

int main()
{
    pthread_cond_init(&cond,NULL);
    pthread_mutex_init(&mutex,NULL);

    pthread_t ida, idb;
    pthread_create(&ida,NULL,funa,NULL);
    pthread_create(&idb,NULL,funb,NULL);

    while( 1 )
    {
        //Keyboard data acquisition - buff
        fgets(buff,128,stdin);
        //Notification thread signal broadcast
        if ( strncmp(buff,"end",3) == 0 )
        {
            pthread_mutex_lock(&mutex);  //Lock
            pthread_cond_broadcast(&cond);  //When you enter end, wake up all threads and let everyone end together. Because threads are at the same level, the exit of the main thread does not affect the operation of child threads (mainly because there is a join function waiting for child threads below)
            pthread_mutex_unlock(&mutex);  //Unlock
            break;
        }

        pthread_mutex_lock(&mutex);
        pthread_cond_signal(&cond);  //Wake up one of the child threads
        pthread_mutex_unlock(&mutex);
    }

    pthread_join(ida,NULL);
    pthread_join(idb,NULL);

    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    exit(0);
}

The two sub threads in the above code are the same. Let's look at the three lines of code in the sub thread:

How many locks are there?         

        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&cond,&mutex);
        pthread_mutex_unlock(&mutex);

How many locks are there in the above three lines of code? Think about it first

There are two locks. Let me stroke them for you. At the moment when the two sub threads function is created, the two sub threads compete for mutually exclusive locks. Only one thread can get the lock. The thread that does not get the lock will enter the blocking. Which thread gets the lock will be bound, and then go to the second line of the code mentioned above, pthread_cond_wait (&cond,&mutex) A mutex lock will be passed in the parameter. By the time of this line, the lock has actually been unlocked, and then it will wait for the signal from the main thread to wake up the thread. The same is true for another thread. At first, it did not get the lock, but after another sub thread is unlocked, the sub thread will wait for wake-up. At this time, the thread that did not get the lock at first will repeat the previous operation Work, and then enter the wait to wake up. However, when waking up, both sub threads are waiting. When waking up, one thread will wake up randomly. At this time, pthread_cond_wait (& cond, & mutex) When this line of code comes out, it will be shackled. Only one child thread can be awakened, and it will be awakened randomly! The thread that has not been awakened has been waiting for it

Topics: Linux Operation & Maintenance server