Lock and condition variables in C++ multithreading tutorial
- 2020-06-12 10:02:27
- OfStack
When doing multithreaded programming, we come across two scenarios:
Multi-threaded access to Shared resources, need to use the lock; State synchronization between multiple threads. Many mechanisms are available. Condition variables are one of the most widely used.Today I will introduce you to the use of locks and condition variables with a simple example.
The code USES C++11
The sample code
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
std::mutex g_mutex; // The global lock used
std::condition_variable g_cond; // The conditional variables used
int g_i = 0;
bool g_running = true;
void ThreadFunc(int n) { // Thread execution function
for (int i = 0; i < n; ++i) {
{
std::lock_guard<std::mutex> lock(g_mutex); // Lock up and leave {} Lock release after scope
++g_i;
std::cout << "plus g_i by func thread " << std::this_thread::get_id() << std::endl;
}
}
std::unique_lock<std::mutex> lock(g_mutex); // lock
while (g_running) {
std::cout << "wait for exit" << std::endl;
g_cond.wait(lock); // wait After the call, the lock is first released and then the wait state is entered. When another process call notification is activated, it is locked again
}
std::cout << "func thread exit" << std::endl;
}
int main() {
int n = 100;
std::thread t1(ThreadFunc, n); // create t1 Thread ( func thread ), t1 Will perform `ThreadFunc` The instructions in
for (int i = 0; i < n; ++i) {
{
std::lock_guard<std::mutex> lock(g_mutex);
++g_i;
std::cout << "plus g_i by main thread " << std::this_thread::get_id() << std::endl;
}
}
{
std::lock_guard<std::mutex> lock(g_mutex);
g_running = false;
g_cond.notify_one(); // Notifying other threads
}
t1.join(); // Waiting for the thread t1 The end of the
std::cout << "g_i = " << g_i << std::endl;
}
After the program is run, the key output is as follows:
plus g_i by main thread 139921025066816
plus g_i by main thread 139921025066816
plus g_i by func thread 139921006847744
plus g_i by func thread 139921006847744
plus g_i by func thread 139921006847744
plus g_i by func thread 139921006847744
plus g_i by func thread 139921006847744
wait for exit // func thread Waiting for the main thread An exit signal from you
plus g_i by main thread 139921025066816
plus g_i by main thread 139921025066816
plus g_i by main thread 139921025066816
plus g_i by main thread 139921025066816
plus g_i by main thread 139921025066816
plus g_i by main thread 139921025066816
plus g_i by main thread 139921025066816
plus g_i by main thread 139921025066816
plus g_i by main thread 139921025066816
plus g_i by main thread 139921025066816
func thread exit
g_i = 200 // The locking mechanism ensures that g_i The right of
As can be seen:
std::this_thread::get_id()
g_i
Introduction of locking method
The code related to locking is:
{
std::lock_guard<std::mutex> lock(g_mutex);
......
}
The point is:
First, this is within 1 local scope, and std::lock_guard is constructed with a call to g_mutex- > lock () method; After the local scope code is finished, std:; The destructor of lock_guard is called, and g_mutex- is called from the function > unlock () method.This is the process of locking and unlocking, why not just call the lock unlock method?
I think this is because if there is a problem with the code in the middle of locking and unlocking that causes the thread function to exit, then the lock cannot be released until another thread handles it badly, causing a deadlock.
Introduction to the use of conditional variables
lock- is called manually before the thread calls ES47en_cond.wait (lock) > lock(), which is implemented by the constructor std::unique_lock; lock- is called when the thread calls ES57en_cond.wait (lock) to wait > unlock() method, so this is also the previous construction of lock using std::unique_lock; g_cond.notify_one (), which notifies one thread, and g_cond.notify_all (), which notifies all threads; The code for the thread to receive notifications is placed in an while loop to prevent the false notifications mentioned in APUE.conclusion