[C++ multithreading series] [8] Condition variables for communication between threads

There are the following scenarios: Thread A needs to wait for thread B to complete the operation before executing it; before thread B completes the operation, thread A is in a sleep state, and when thread B completes the operation, it wakes up thread A. Here, note that before thread B is completed, A is in a sleep state, that is, at this time, A does not occupy the CPU, and cannot use atomic variables + while infinite loop to wait (while (! done)), so that the CPU will be running all the time condition.

Sleep can be used to handle this, but since A does not know how long it takes to sleep, sleep is not suitable. Condition variables are used here to deal with this problem.

Condition variable: When receiving a notify notification, check whether a certain condition is met. When it is met, the thread stops waiting, wakes up, re-locks, and continues to execute.

The overall process is as follows, see the code comments for details

#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
using namespace std;

// 使用条件变量的三剑客:
/*
1.互斥元
2.条件变量
3.条件值done
*/
mutex mA;
condition_variable cv;
bool done = false;

void f()
{
	unique_lock<mutex> _1(mA);
	// 条件变量的wait所必须是unique_lock而不是lock_guard,因为wait会在内部调用unique_lock.unlock先解锁,当被唤醒后,条件满足时,会unique_lock.lock
	// 条件为:当done为true时,收到notify的线程会被唤醒,否则即使收到notify,也不会被唤醒
	cv.wait(_1, [] {return done; });
	cout << "has done" << endl;

	// 需要手动释放锁
	_1.unlock();
}

void f2()
{
	// 这里使用lock_guard在mA上加锁即可
	lock_guard<mutex> _1(mA);
	cout << "f2" << endl;
	std::this_thread::sleep_for(1s);

	//必须将条件done设置为true,否则线程t1不会被唤醒
	done = true;

	//通知一个线程,让收到的线程检查其条件,收到通知的线程发现条件满足,则该线程会被唤醒
	cv.notify_one();
}


int main(int argc, int * argv[])
{
	thread t1(f);

	thread t2(f2);

	t1.join();
	t2.join();

	cout << "main" << endl;
	system("pause");
}

The result is as follows:

 

Note that if you forget to set done to true in f2, f1 will not be woken up and will keep waiting:

void f2()
{
	// 这里使用lock_guard在mA上加锁即可
	lock_guard<mutex> _1(mA);
	cout << "f2" << endl;
	std::this_thread::sleep_for(1s);

	//必须将条件done设置为true,否则线程t1不会被唤醒
	//done = true;

	//通知一个线程,让收到的线程检查其条件,收到通知的线程发现条件满足,则该线程会被唤醒
	cv.notify_one();
}

The result is as follows:

 

So: The essence of the condition variable is that only when the condition is met, the thread will be awakened, not notify, and the waiting thread will be awakened.

 

Condition variables actually implement the data sharing operation between threads, namely done. After thread A modifies some data, it notifies thread B to obtain the latest data modification value through the condition variable.

The code can be as follows:

#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
using namespace std;

// 使用条件变量的三剑客:
/*
1.互斥元
2.条件变量
3.条件值done
*/
mutex mA;
condition_variable cv;
bool done = false;

int age = 0;

void f()
{
	unique_lock<mutex> _1(mA);
	// 条件变量的wait所必须是unique_lock而不是lock_guard,因为wait会在内部调用unique_lock.unlock先解锁,当被唤醒后,条件满足时,会unique_lock.lock
	// 条件为:当done为true时,收到notify的线程会被唤醒,否则即使收到notify,也不会被唤醒
	cv.wait(_1, [] {return done; });
	cout << "has done" << endl;
	cout << "age=" << age << endl;
	// 需要手动释放锁
	_1.unlock();
}

void f2()
{
	// 这里使用lock_guard在mA上加锁即可
	lock_guard<mutex> _1(mA);
	cout << "f2" << endl;
	std::this_thread::sleep_for(1s);

	age = 1000;
	//必须将条件done设置为true,否则线程t1不会被唤醒
	done = true;

	//通知一个线程,让收到的线程检查其条件,收到通知的线程发现条件满足,则该线程会被唤醒
	cv.notify_one();
}


int main(int argc, int * argv[])
{
	thread t1(f);

	thread t2(f2);

	t1.join();
	t2.join();

	cout << "main" << endl;
	system("pause");
}

age as a shared variable for both threads

The result is as follows:

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325218495&siteId=291194637