当获取 Mutex 的线程退出时,Mutex 会发生什么?

17

假设有两个线程,主线程和B线程(由主线程创建)。如果B线程获取了一个互斥锁(如pthread_mutex)并在未解锁该锁的情况下调用了pthread_exit。那么这个互斥锁会发生什么?它会变得可用吗?

假设B线程已经获得了锁并没有对锁进行解锁,当它调用pthread_exit时,锁将保持被锁定状态。其他任何尝试获得相同锁的线程都将被阻塞,直到该锁被释放为止。因此,在这种情况下,互斥锁不会变得可用,而是保持被锁定状态,直到被当前占用锁的线程解锁。
2个回答

17

不行。互斥锁仍然被锁定。这种锁的实际行为取决于它的类型,您可以在这里这里阅读相关信息。


1
哇,一个没有线程亲和力的“互斥锁”?没有“废弃”的错误状态? - Hans Passant
3
一般来说,不需要。普通互斥锁甚至不需要知道哪个线程锁定了它;获取并存储这些信息会使其变得不必要地慢。当然,如果实现要永久保留已死线程的ID并防止其重用,又怎么能不耗尽ID呢? POSIX提供了专门的鲁棒互斥锁,如果需要这种功能,可以创建它们,但它们通常会更加缓慢并使用更多资源(可能是用户空间和内核空间)。 - R.. GitHub STOP HELPING ICE
1
那么一个试图获取它已经拥有的互斥锁的线程会导致死锁吗?编程真是太难了。在pthread中有任何可重入锁定吗? - Hans Passant
1
@Hans:当然可以:pthread_mutexattr_settype(PTHREAD_MUTEX_RECURSIVE) - SingleNegationElimination
1
@Hans:你需要一个递归互斥锁。普通的互斥锁不是递归的。需要递归互斥锁通常意味着你的代码持有锁的时间太长,在负载下会有非常严重的竞争问题。 - R.. GitHub STOP HELPING ICE
这个链接已经失效,请更换。 - Abhishek Gupta

16
如果在调用pthread_mutex_init之前设置了正确的属性来创建一个健壮的互斥锁,当持有锁的线程终止时,互斥锁将进入特殊状态,下一个尝试获取互斥锁的线程将会得到EOWNERDEAD的错误。此时,它需要清理互斥锁保护的任何状态并调用pthread_mutex_consistent使互斥锁再次可用,或者调用pthread_mutex_unlock(这将使互斥锁永久不可用;进一步尝试使用它将返回ENOTRECOVERABLE)。
对于非健壮的互斥锁,如果锁定它的线程在没有解锁的情况下终止,那么该互斥锁将永久不可用。根据标准(参见Austin Group跟踪器上的issue 755解决方案),互斥锁仍然被锁定,并且其正式所有权仍然属于退出的线程,任何尝试锁定它的线程都将死锁。如果另一个线程尝试解锁它,则通常是未定义行为,除非互斥锁是使用PTHREAD_MUTEX_ERRORCHECK属性创建的,在这种情况下将返回一个错误。
另一方面,许多(大多数?)实际实现并不真正遵循标准的要求。从另一个线程尝试锁定或解锁互斥锁可能会出现虚假成功,因为线程ID(用于跟踪所有权)可能已被重用,现在可能引用不同的线程(可能是发出新的锁定/解锁请求的线程之一)。至少glibc的NPTL已知会表现出这种行为。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接