如果 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,但您不能依赖它来移植。
所以假设有 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 ofpthread_mutex_unlock
operations must be performed before the mutex returns to the unlocked state.
根据文档,在 Linux 中,默认类型是 fast,但您不能依赖它来移植。