-
mutex
头文件是<mutex>,mutex是用来保证线程同步的,防止不同的线程同时操作同一个共享数据。mutex 对象只能在同一线程进行一次加锁并对应一次解锁,否则程序抛出异常。mutex不能在同一个线程中多次加锁的试验。
- td::mutex,最基本的 Mutex 类。
- std::recursive_mutex,递归 Mutex 类。
- std::time_mutex,定时 Mutex 类。
- std::recursive_timed_mutex,定时递归 Mutex 类。
但是使用mutex是不安全的,当一个线程在解锁之前异常退出了,那么其它被阻塞的线程就无法继续下去。
try_lock()
尝试锁住互斥量,如果互斥量被其他线程占有,则当前线程也不会被阻塞。线程调用该
函数也会出现下面 3 种情况,(1). 如果当前互斥量没有被其他线程占有,则该线程锁住互斥量,直
到该线程调用 unlock 释放互斥量。(2). 如果当前互斥量被其他线程锁住,则当前调用线程返回
false,而并不会被阻塞掉。(3). 如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)。
lock()
调用线程将锁住该互斥量。线程调用该函数会发生下面 3 种情况:(1). 如果该互斥量当前没
有被锁住,则调用线程将该互斥量锁住,直到调用 unlock之前,该线程一直拥有该锁。(2). 如果当
前互斥量被其他线程锁住,则当前的调用线程被阻塞住。(3). 如果当前互斥量被当前调用线程锁
住,则会产生死锁(deadlock)。
unlock(),:
解锁,释放对互斥量的所有权。
recursive_mutex
递归的独占互斥量,允许同一个线程,同一个互斥量,多次被lock,用法和非递归的一样 跟windows的临界区是一样的,但是调用次数是有上限的,效率也低一些
timed_mutex
带超时的互斥量,独占互斥量 这个就是拿不到锁会等待一段儿时间,但是超过设定时间,就继续执行
recursive_timed_mutex
带超时的,递归的,独占互斥量,允许同一个线程,同一个互斥量,多次被lock,用法和非递归的一样
recursive_timed_mutex/timed_mutex的几个函数
try_lock_for();是等待一段时间,参数是时间段try_lock_until();参数是一个时间点,到那个时间点之前等待获取锁,
std::lock_guard
使用lock_guard则相对安全,它是基于作用域的,能够自解锁,当该对象创建时,它会像m.lock()一样获得互斥锁,当生命周期结束时,它会自动析构(unlock),不会因为某个线程异常退出而影响其他线程
unique_lock,lock_guard的区别
unique_lock与lock_guard都能实现自动加锁和解锁,但是前者更加灵活,能实现更多的功能。
unique_lock可以进行临时解锁和再上锁,如在构造对象之后使用lck.unlock()就可以进行解锁, lck.lock()进行上锁,而不必等到析构时自动解锁。
递归互斥量std::recursive_mutex
递归锁允许同一个线程多次获取该互斥锁,可以用来解决同一线程需要多次获取互斥量时死锁的问题。
虽然递归锁能解决这种情况的死锁问题,但是尽量不要使用递归锁,主要原因如下:
1. 需要用到递归锁的多线程互斥处理本身就是可以简化的,允许递归很容易放纵复杂逻辑的产生,并 且产生晦涩,当要使用递归锁的时候应该重新审视自己的代码是否一定要使用递归锁;
2. 递归锁比起非递归锁,效率会低;
3. 递归锁虽然允许同一个线程多次获得同一个互斥量,但可重复获得的最大次数并未具体说明,一旦 超过一定的次数,再对lock进行调用就会抛出std::system错误。