Lock

mutex mut;
mut.lock();
sharedVariable++;
mut.unlock();

RAII, Resource Acquisition Is Initialization, 资源获取即初始化

RAII,全称为Resource Acquisition Is Initialization,汉语是“资源获取即初始化”。简单说来就是,在资源获取的时候将其封装在某类的object中,利用”栈资源会在相应object的生命周期结束时自动销毁”来自动释放资源,即,构造函数创建时初始化获取资源,并将资源释放写在析构函数中。所以这个RAII其实就是和智能指针的实现是类似的。

lock_guard (推荐使用) & std::mutex

lock_guard取代了mutex的lock() 和 unlock() 的函数。虽然std::mutex可以对多线程编程中的共享变量提供保护,但是直接使用std::mutex的情况并不多。因为仅使用std::mutex有时候会发生死锁。回到上边的例子,考虑这样一个情况:假设线程1上锁成功,线程2上锁等待。但是线程1上锁成功后,抛出异常并退出,没有来得及释放锁,导致线程2“永久的等待下去”(线程2:我的心在等待永远在等待……),此时就发生了死锁。std::lock_guard只有构造函数和析构函数。简单的来说:当调用构造函数时,会自动调用传入的对象的lock()函数,而当调用析构函数时,自动调用unlock()函数(这就是所谓的RAII)。

mutex mut;
{
    lock_guard<mutex> lockGuard(mut);  // lock in lock_guard 构造函数
    sharedVariable++;
}  // unlock in lock_guard 析构函数

unique_lock

unique_lock:这是C++11中一个更灵活的锁,它允许手动锁定和解锁互斥量,以及与条件变量一起使用(是lock_guard的进阶版)。与 lock_guard 类似,unique_lock 也是一个 RAII 风格的锁,当对象离开作用域时,它会自动解锁互斥量。unique_lock 还支持延迟锁定、尝试锁定和可转移的锁所有权。unique_lock 是一个类模板,工作中,一般使用lock_guard(推荐使用);lock_guard取代了mutex的lock() 和 unlock() 的函数。

condition_variable 条件变量

互斥量是多线程间同时访问某一共享变量时,保证变量可被安全访问的手段。但单靠互斥量无法实现线程的同步。线程同步是指线程间需要按照预定的先后次序顺序进行的行为。C++11对这种行为也提供了有力的支持,这就是条件变量。条件变量位于头文件condition_variable下。条件变量是允许多个线程相互交流的同步原语。它允许一定量的线程等待(可以定时)另一线程的提醒,然后再继续。条件变量始终关联到一个互斥。条件变量使用过程:

  1. 拥有条件变量的线程获取互斥量。
  2. 循环检查某个条件,如果条件不满足则阻塞直到条件满足;如果条件满足则向下执行。
  3. 某个线程满足条件执行完之后调用notify_one或notify_all唤醒一个或者所有等待线程。

     #include <iostream>
     #include <condition_variable>
    
     using namespace std;
    
     mutex wait_mutex;
     condition_variable wait_condition_variable;
    
     // 等待线程函数
     void wait_thread_func()
     {
         unique_lock<mutex> lock(wait_mutex);
         cout << "等待线程(" << this_thread::get_id() << "): 开始等待通知..." << endl;
         wait_condition_variable.wait(lock);
         cout << "等待线程(" << this_thread::get_id() << "): 继续执行代码..." << endl;
     }
    
     int main()
     {
         thread wait_thread(wait_thread_func);
    
         this_thread::sleep_for(1s); // 等待1秒后进行通知
         cout << "通知线程(" << this_thread::get_id() << "): 开始通知等待线程..." << endl;
         wait_condition_variable.notify_one();
         wait_thread.join();
         cout << "--- main结束 ---" << endl;
     }