如果 C 中的线程试图获取它已经拥有的锁,会发生什么情况?

What happens if a thread in C tries to acquire a lock it already has?

所以假设有 1 个线程, 线程通过以下方式获取锁:

pthread_mutex_lock(&lock);

然后在解锁之前,它再次到达一行:

pthread_mutex_lock(&lock);

pthread库会阻塞线程的推进,还是会识别线程已经持有锁,从而放过?

POSIX 支持多种变体中的许多不同互斥锁类型。都使用相同的 pthread_mutex_t 类型,因此无法判断 pthread_mutex_lock 在重新锁定已被当前线程获取的锁时做了什么。

常见行为包括:

  • 常规互斥体的自死锁(pthread_mutex_lock 从不 returns)。
  • 错误检查互斥锁的错误(pthread_mutex_lock returns 带有错误代码)。
  • 锁定操作成功,在锁定可供其他线程锁定(递归互斥锁)之前需要再进行一次解锁操作。

当使用属性 pthread_mutex_init 创建互斥量时,可以选择互斥量行为;参见 pthread_mutexattr_init。一些系统还提供非标准初始化程序,例如创建不同变体的标准 PTHREAD_MUTEX_INITIALIZER 初始化程序。

行为取决于互斥体的种类。 POSIX standard 表示递归锁定行为取决于锁的类型

If a thread attempts to relock a mutex that it has already locked, pthread_mutex_lock() shall behave as described in the Relock column of the following table.

Relock 专栏说

  • PTHREAD_MUTEX_NORMAL 类型的互斥锁可能会死锁
  • PTHREAD_MUTEX_ERRORCHECK 类型的互斥锁应return 错误
  • PTHREAD_MUTEX_RECURSIVE 类型的互斥体将用作递归锁,您必须在锁定它的同时解锁多次
  • 类型 PTHREAD_MUTEX_DEFAULT 的互斥体将具有 未定义的行为 ,这实际上意味着如果在该平台上默认锁是前 3 种类型中的任何一种,它将具有如上列中的特征,如果是其他类型,则行为将是未定义的。

因此,测试一个PTHREAD_MUTEX_DEFAULT锁来找出行为是什么尤其没有意义。

Linux manuals pthread_mutex_lock(3) 改写如下:

If the mutex is already locked by the calling thread, the behavior of pthread_mutex_lock depends on the kind of the mutex. If the mutex is of the fast kind, the calling thread is suspended until the mutex is unlocked, thus effectively causing the calling thread to deadlock. If the mutex is of the error checking kind, pthread_mutex_lock returns immediately with the error code EDEADLK. If the mutex is of the recursive kind, pthread_mutex_lock succeeds and returns immediately, recording the number of times the calling thread has locked the mutex. An equal number of pthread_mutex_unlock operations must be performed before the mutex returns to the unlocked state.

根据文档,在 Linux 中,默认类型是 fast,但您不能依赖它来移植。