(十)线程同步

1. 线程同步的使用原则

  • 首要尽量最低限度共享对象,减少需要同步的场合,避免一个对象暴露给别的线程;
  • 其次是使用高级的并发编程构件,如线程安全的队列等;
  • 最后不得已必须使用底层同步原语来保护共享对象时,只使用非递归的互斥锁和条件变量;

2. 互斥锁

参考: std::mutex

互斥锁单独使用,主要是为了保护共享数据.
std::mutex的使用原则是, 使用RAII手法封装mutex的创建/销毁/加锁/解锁这四个操作, 保证锁的生效期间等于一个作用域, 不会因异常而忘记解锁. RAII能够保证加锁/解锁在同一个线程, 能够保证自动解锁和避免重复解锁.

std::lock_guard 是互斥封装器,为在作用域块期间占有互斥提供便利 RAII 风格机制。
参考std::lock_guard

std::unique_lock 是通用互斥包装器,允许延迟锁定、锁定的有时限尝试、递归锁定、所有权转移和与条件变量一同使用。
参考std::unique_lock

3. 条件变量

参考: std::condition_variable

条件变量就是一个或多个线程等待某个布尔表达式为真,即等待别的线程"唤醒"它.
条件变量只有一种正确使用的方式:

  • 对于wait端:
    • 必须与mutex一起使用, 该布尔表达式的读写需受此mutex保护;
    • 在mutex已上锁时才能调用wati();
    • 把判断布尔条件和wait()放到while循环中. 必须使用while循环来等待条件变量,而不能用if语句,原因是spurious wakeup(虚假唤醒).
  • 对于notify端:
    • 在notify前一般要修改布尔表达式;
    • 修改布尔表达式通常要用mutex保护;
    • 区分notify_one和notify_all.
posted @ 2018-07-27 00:28  yvhqbat  阅读(124)  评论(0编辑  收藏  举报