lock.trylock详解

发布时间:2023-05-19

一、lock.trylock带参数

lock.trylock 方法是用来获取锁的,比较常用并且非阻塞。如果锁已经被其他线程获取,那么方法直接返回 false。如果锁没有被其他线程获取,那么方法获取锁并且直接返回 true。 在 C++11 中,lock.trylock 方法可以传递一个 std::adopt_lock_t 类型的参数,通过这个参数告知方法获取锁并且托管给 std::unique_lock 对象。下面是一个典型的例子:

std::mutex m;
std::unique_lock<std::mutex> lock(m, std::try_to_lock);
if (lock.owns_lock()) {
    // ...
}

在上面的例子中,unique_lock 对象会尝试获取锁,如果获取成功,那么该对象会托管 std::mutex 对象并且进行使用。

二、lock.trylock三个参数

在 C++11 中,lock.trylock 方法也可以传递三个参数。下面是三个参数的含义:

  1. lock.trylock(m):尝试获取锁,如果锁已经被其他线程获取,那么方法直接返回 false
  2. lock.trylock(m, std::defer_lock):创建 unique_lock 对象但不获取锁。
  3. lock.trylock(m, std::try_to_lock):尝试获取锁,如果锁已经被其他线程获取,那么方法直接返回 false。 在以上三个参数中,std::defer_lock 是最常用的。下面是一个典型的例子:
std::mutex m;
std::unique_lock<std::mutex> lock(m, std::defer_lock);
if (lock.try_lock()) {
    // ...
}

在上面的例子中,unique_lock 对象不会尝试获取锁。当 unique_lock 对象调用 try_lock 方法时,对象会尝试获取锁。

三、lock.trylock后再lock会报错吗

在 C11 和 C17 中,lock.trylock 获取锁后,如果锁已经被其他线程获取,那么方法会直接返回 false 而不是阻塞调用线程。因此,在获取锁前没有任何问题。 每个线程在获取锁后,需要在规定的时候释放锁。在释放锁前,不能再次锁定相同的锁。下面是一个例子:

std::mutex m;
std::unique_lock<std::mutex> lock(m);
if (lock.try_lock()) {
    // ...
    lock.unlock();
}
lock.lock();  //会报错

在上面的例子中,unique_lock 对象首先尝试获取锁并且成功,然后执行一些代码,最后释放锁。但是在释放锁后,该线程又再次尝试获取相同的锁。这时候会产生死锁。