使用std :: try_to_lock

时间:2018-08-16 13:03:07

标签: c++ multithreading c++11 locking mutex

当我尝试运行以下代码时,我得到令人惊讶且矛盾的行为。

#include <iostream>
#include <mutex>

int main() {
    std::mutex mtx;
    std::unique_lock<std::mutex> lock1(mtx);
    std::unique_lock<std::mutex> lock2(mtx, std::try_to_lock);

    std::cout << "lock1 owns lock: " << lock1.owns_lock() << std::endl;
    std::cout << "lock2 owns lock: " << lock2.owns_lock() << std::endl;
}

当我在计算机上(装有clang ++ 4.0.1或g ++ 7.3.0的Linux)运行此命令时,它会打印出lock1lock2都拥有锁(令人惊讶)。当我在cpp.sh上运行时,它说lock1确实拥有,但是lock2不拥有锁(我所期望的)。

所有人都使用C ++ 11和-Wall,而没有进行优化。

2 个答案:

答案 0 :(得分:12)

documentation中针对std::unque_lock构造函数所述:

  

5)尝试通过调用m.try_lock()锁定相关的互斥锁而不会阻塞。 如果当前线程已经拥有互斥锁,则该行为是不确定的,除非互斥锁是递归的。

重点是我的。由于std::mutex不是递归的,因此您拥有UB-std::mutex::try_lock()

  

如果try_lock由已经拥有互斥锁的线程调用,则行为未定义。

答案 1 :(得分:0)

正如在这里回答的那样,根据C ++标准,锁定当前线程已经拥有的互斥锁是未定义的行为,但是似乎您知道您的实现基于POSIX线程,这具有一组不同的要求:

  

pthread_mutex_trylock()函数应等效于   pthread_mutex_lock(),但如果互斥对象引用为   互斥锁当前已被锁定(被任何线程锁定,包括当前   线程),该调用应立即返回。

您正在观察的内容很可能是由于您未使用-pthread标志来构建代码所致。 GNU C ++库检测程序是否针对libpthread.so进行了链接,如果不是,则对lock / unlock函数的所有调用都变为无操作。

您可以找到一些信息here

  

__gthread_mutex_lock是一种单行函数,可转发到pthread_mutex_lock。如果您不链接到libpthread.so,请使用GNU libc   那么 pthread_mutex_lock是一项无操作的功能,。它是   调用它比花时间检查线程是否更快速   活跃。

或者您可以自己检查头文件中的std::mutex::lock的源代码。您将看到类似这样的内容:

void
lock()
{
  int __e = __gthread_mutex_lock(&_M_mutex);

  // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
  if (__e)
     __throw_system_error(__e);
}

static inline int
__gthread_mutex_lock (__gthread_mutex_t *__mutex)
{
  if (__gthread_active_p ())
    return __gthrw_(pthread_mutex_lock) (__mutex);
  else
    return 0;
}

如果当前过程中不存在__gthread_active_p,则函数0将返回libpthread.so,从而使互斥锁锁定为无操作。

添加-pthread可以解决您的问题,但您不应该依赖此-正如您的情况所证明的那样。