Talk about conditional variables of Linux threads

Condition variables are used to synchronize threads. How to synchronize? Let's look down

Conditional variable correlation function

#include <pthread.h>
int pthread_cond_init(pthread_cond_t* cond, const pthread_condattr_t* condattr); 	//Initialize condition variable
int pthread_cond_destroy(pthread_cond_t* cond); 	//Destroy condition variable
int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex); 	//Wait condition variable
int pthread_cond_signal(pthread_cond_t* cond); 		//Wake up a thread waiting for the condition variable
int pthread_cond_broadcast(pthread_cond_t* cond); 	//Wake up all threads waiting for the condition variable

pthread_cond_init,pthread_cond_destroy won't explain more.

pthread_cond_wait

pthread_cond_wait completes the following steps in sequence:

  1. Add the current thread to the waiting queue of condval
  2. Release mutex
  3. Blocking waiting signal occurs
  4. Wake up the thread after capturing the signal
  5. Get mutex (lock)

If step 2 fails, it will immediately wake up the thread and return the error code. If step 5 fails to lock, it will return the error code.
Call pthread_ cond_ Before waiting, you need to lock the mutex first. One reason is step 2, and the other reason is to see later.

pthread_cond_signal and pthread_cond_broadcast

pthread_cond_signal and pthread_cond_broadcast is used to wake up the threads in the condval waiting queue. The former wakes up only one thread, and the latter wakes up all threads in the queue. Before calling these two functions, you generally need to get mutex to change the condition, which is pthread_ cond_ The second reason for mutex must be obtained before the wait call to prevent the condition from changing during putting the thread into the wait queue.

Classic application

A classic example is the producer consumer problem. One production thread is responsible for adding data to the message queue, and multiple consumption threads are responsible for obtaining consumption data from the message queue. After obtaining the lock, the production thread adds data to the message queue (condition changes), releases the lock, and calls pthread_cond_signal notifies the consuming thread of a condition change. One of the threads receives the signal and starts processing the data. The code is not written.

Online viewpoint verification

See some articles on the Internet that say pthread_ cond_ After the signal is sent, all waiting threads will receive the signal. Since the signal needs to be locked after being captured, only one thread grabs the mutex, and other threads are blocked in step 5 above. Is that right? Look at the severity code below

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

//Global mutexes and conditional variables
pthread_mutex_t mutex;
pthread_cond_t cond;

// What each worker thread has to do is wait for the condition variable to change
void* work_thread(void* arg)
{
	int index = *(int*)arg + 1;
	while (1)
	{
		//Grab mutex
		pthread_mutex_lock(&mutex);
		//Successfully snatch the blocking lock and wait for the signal to occur
		printf("thread %d grib mutex\n", index);
		pthread_cond_wait(&cond, &mutex);
		//The signal came, I grabbed it, added a print display, and then released the lock
		printf("thread %d grib condval\n", index);
		pthread_mutex_unlock(&mutex);
		sleep(1);
	}
}

int main()
{
	pthread_t pthreads[5];
	//Initialize mutexes and condition variables
	pthread_mutex_init(&mutex, NULL);
	pthread_cond_init(&cond, NULL);
	//Create worker thread
	for (int i = 0; i < 5; ++i)
	{
		pthread_create(&pthreads[i], NULL, work_thread, (void*)&i);
		//Here, sleep is to ensure that each thread can correctly receive the parameter value
		sleep(1);
	}
	//Wait for 2s, and then the main thread starts to send a signal regularly for the working thread to grab
	sleep(7);
	while (1)
	{
		printf("main thread send signal\n");
		pthread_cond_signal(&cond);
		sleep(4);
	}

	pthread_exit(0);
	return 0;
}

Here is the output over a period of time

According to the above statement, when a worker thread grabs the signal and releases the lock, another worker thread should be freed from the previous step 5, that is, from pthread_cond_wait returns. However, it can be seen from the above output that this is not the case. The output of "thread XX grid condval" is after a send signal. So other threads are still blocked in step 3 instead of 5.

Keywords: C++ Linux Multithreading server

Added by traffic on Wed, 05 Jan 2022 06:10:59 +0200