Mutex lock condition variable

Mutex lock condition variable

In C++, mutex and condition variables are important tools for thread synchronization and communication. Mutex locks are used to protect shared data structures to ensure that only one thread can access the data structure at any time. Condition variables are used to communicate between threads, allowing one thread to wait for a specific condition to be true and then be awakened by another thread.

Mutex locks are implemented in C++ through the std::mutex class. It provides lock() and unlock() methods, which can be used to protect shared data. When a thread calls the lock() method, if the mutex is already locked by another thread, the thread will be blocked until the lock is released. Once the thread acquires the lock, it executes the critical section of code and uses the unlock() method to release the lock when exiting the critical section. This ensures that only one thread is accessing the shared resource at any time.

Condition variables are implemented in C++ through the std::condition_variable class. Condition variables are used for communication between threads. A thread can suspend itself by waiting for a condition variable, release the lock it already holds, and wait for other threads to send a wake-up signal after meeting a specific condition. Other threads can send wake-up signals through the notify_one() or notify_all() method when the conditions are met. The awakened thread will retry to acquire the mutex and continue execution.

Here is an example using a mutex and condition variables:

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void worker()
{
    
    
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, []() {
    
     return ready; });
    std::cout << "Worker thread is executing." << std::endl;
    // 执行相关操作
}

int main()
{
    
    
    std::thread t(worker);
    
    // 做一些任务
    
    {
    
    
        std::lock_guard<std::mutex> lock(mtx);
        ready = true;
    }
    cv.notify_one();
    
    t.join();
    
    return 0;
}

The main thread creates a worker thread and waits for the condition variable ready to be satisfied inside the worker thread. The main thread sets ready to true after some tasks and wakes up the worker thread using cv.notify_one(). After the worker thread wakes up, acquires the mutex lock, outputs a message, and performs the rest of the operations.

Here is a simple example of a mutex lock and condition variable to illustrate their basic usage. In actual applications, you may need more complex synchronization and communication solutions, which can be achieved using multiple mutex locks, condition variables, and other synchronization primitives.

lock_guard function explanation

std::lock_guard is a RAII (resource acquisition is initialization) class, which provides a mechanism to automatically acquire a mutex lock, which can easily protect critical sections.

When using a std::lock_guard object, the mutex lock is acquired in the object's constructor and released in the object's destructor. This ensures that the mutex will be released correctly under any circumstances (including exception throws and early returns), thus preventing resource leaks and deadlocks.

The typical usage of std::lock_guard is to create a std::lock_guard object between the beginning and end of the critical section. When creating a std::lock_guard object, you need to pass a mutex object as a parameter. For example:

std::mutex mtx;
// ...其他代码...

{
    
    
    std::lock_guard<std::mutex> lock(mtx);
    // 临界区代码
    // 互斥锁在这里被自动获取
    // 无论代码中是否有异常或提前返回,互斥锁都会在这里被释放
}
// ...其他代码...

In the above example, the std::lock_guard object is created in a scope and named lock. Within the scope of the lock object, you can freely access the shared resources of the critical section. When the lock object goes out of its scope, its destructor is called and the mutex lock is automatically released.

Using std::lock_guard has the following benefits compared to manually calling the lock() and unlock() methods:

Simplicity: Using std::lock_guard can put the operations of acquiring and releasing mutex locks in the same scope, making the code logic clearer and more concise.
Exception safety: The std::lock_guard object acquires the mutex lock when it is constructed. Regardless of whether there is an exception, its destructor will be called to release the mutex lock to ensure exception safety.
Prevent forgetting to release the lock: Since the lock is released automatically, there is no need to manually call the unlock() method, thus avoiding the deadlock problem caused by forgetting to release the lock.
It should be noted that std::lock_guard is an exclusive lock method. It uses std::mutex (mutex lock) instead of std::shared_mutex (shared mutex lock). If you need to share locks between multiple threads, you need to use std::shared_lock or std::unique_lock instead of std::lock_guard.

Guess you like

Origin blog.csdn.net/neuzhangno/article/details/131521027