Boost库学习(3)thread 2

互斥锁

多线程编程时基本上都会用到的东西。当线程a和线程b都要访问数据X时,在所有访问数据X的地方都要用互斥锁保护起来,只在其中一个线程加上互斥锁保护是没有作用的。(只有一种情况下可以不加锁,即只有一个线程会修改数据,其它线程只读取数据时,修改数据的线程在读取时不需要加锁,因为它在读取时不可能同时存在写操作。例如,线程a会读写数据X,而线程b只会读数据X时,线程a在读数据的时候就可以不加锁保护。)

互斥锁的种类

  • mutex和recursive_mutex
    支持的方法有lock(),try_lock(),unlock()。try_lock会立即返回(可能成功也可能失败),而lock会等到成功(即别人unlock)才返回。
    recursive_mutex与mutex相比,它允许同一个线程多次加锁。主要是用于加锁后调用另一个函数,而被调用的这个函数里面又对同一个mutex进行加锁处理。这种情况下,如果是用的mutex,则在内层函数中的lock()处理时会发生死锁。
  • timed_mutex和recursive_timed_mutex
    支持的方法比上面一种多2个,try_lock_for()和try_lock_until()。多出来的2个函数与try_lock功能一样,只是不是立即返回,而是等到成功或者TimeOut为止。
    recursive_timed_mutex和timed_mutex的差别,与recursive_mutext和mutex的差别相同。

    互斥锁工具类

    实际编写代码时,并不推荐直接使用上面的各种互斥锁。原因很简单,直接使用互斥锁的话,需要保证各种异常情况下,互斥锁都被释放了;而使用互斥锁的工具类就没有这个问题,在工具类对象释放的时候会自动释放互斥锁。
  • lock_guard
    它的对象在生存过程中(从申明开始到变量被回收)一直处于互斥锁锁定状态。申明有两种形式:
    boost::lock_guard lg(Lockable &m); // 申明时调用lock
    boost::lock_guard lg(Lockable &m,boost::adopt_lock); // 表示互斥锁m已经处于lock成功的状态
  • unique_guard
    它的对象在生存过程中,可以多次切换锁定和非锁定状态。申明有五种形式:
    boost::unique_lock ul(Lockable &m); // 与lock_guard的方式一相同
    boost::unique_lock ul(Lockable &m,boost::adopt_lock); // 与lock_guard的方式二相同
    boost::unique_lock ul(Lockable &m,boost::defer_lock); // 只申明,需要手动调用lock系列函数
    boost::unique_lock ul(Lockable &m,boost::try_to_lock); // 申明并调用try_lock
    boost::unique_lock ul(TimedLockable &m,boost::chrono::XXX(n)); // 申明并调用try_lock_for

信号量

信号量用于多线程的同步。例如生产消费类问题,消费者每次处理一个数据,没有数据时进入等待状态,生产者每生产一个数据,则将消费者唤醒。

<!-- lang: cpp -->
boost::condition_variable cond;
boost::mutex mut;
bool data_ready;
void wait_for_data_to_process()
{
    boost::unique_lock<boost::mutex> lock(mut); // 这里不能用lock_guard
    while(!data_ready)
    {
        cond.wait(lock);  // cond.wait(lock)相当于先mux.unlock(),然后等到别的地方调用到了cond.notify_XXX()后,再mut.lock(),因此不能用lock_guard(lock_guard的整个生存过程中一直处于锁定状态)
    }
    process_data();
}
void prepare_data_for_processing()
{
    retrieve_data();
    prepare_data();
    {
        boost::lock_guard<boost::mutex> lock(mut); // 申明时自动调用mut.lock()
        data_ready=true;
    } // 这里会自动回收局部变量lock,也就是说这里会调用mut.unlock()
    cond.notify_one();
}

只运行一次的处理

<!-- lang: cpp -->
boost::once_flag once;
void once_func();
void test()
{
    boost::call_once(once,once_func); // 只会成功执行一次,如果有多个线程同时调用这里,则后调用的线程进入等待状态,直到第一个线程成功或者失败(抛出异常),第一个线程成功则其它线程跳过这一行,失败则由另一个线程执行这里的处理。
}

你可能感兴趣的:(C++,boost)