繁体   English   中英

具有互斥锁的多个锁和可能发生死锁

[英]Multiple locks with mutex and the possibility of a deadlock

我是线程新手并试图理解互斥锁。
我理解互斥锁是一个只被一个线程挑选的对象(密钥)(如果它被挑选然后其他线程无法选择它并且必须等待)来访问我们想要锁定的代码的某些部分。
因此,当时只有一个线程可以访问该锁定的代码部分(例如共享计数器)。 其他线程必须等到互斥锁解锁等等。

Mutex1.Lock();
 {
     Mutex2.Lock();
     {
          // Code locked by mutex 1 and 2.
     }
     Mutex2.Unlock();

     // Code locked by mutex 1.
 }
 Mutex1.Unlock();

如果我写多个互斥锁会发生什么?
这两个互斥锁是否会被同一个线程选中? 我还读到多个互斥锁可能导致死锁。
谁能解释并提供一个例子,说明如何通过用2个互斥锁锁定部分代码来导致死锁?

以下是对您描述的内容进行编码的安全方法:

std::mutex Mutex1;
std::mutex Mutex2;

void
test()
{
    using namespace std;
    lock(Mutex1, Mutex2);  // no deadlock!
    lock_guard<mutex> lk1{Mutex1, adopt_lock};
    {
        lock_guard<mutex> lk2{Mutex2, adopt_lock};
        // Code locked by mutex 1 and 2.
    }   // lk2.unlock()
    // Code locked by mutex 1.
}   // lk1.unlock()

此代码无法死锁,因为std::lock(Mutex1, Mutex2)锁定两个互斥锁,同时避免死锁(通过某些内部算法)。 使用std::lock一个优点是您不必记住锁定互斥锁所需的顺序(这使得在大型代码库中维护更容易)。 但缺点是您需要在代码中的单个点锁定两个锁。 如果您无法同时锁定它们,那么您必须按照其他答案描述的那样回退到订购。

此代码也是异常安全的,因为如果在任何地方抛出任何异常,则在异常传播时解锁任何被锁定的内容。

一个线程可以容纳多个锁,是的。 即使它只获得了一个互斥锁,也可能发生死锁。查看工作流程:

线程A.

. 
.
.
lock mutex1
.
<---- Context switch! ----->

线程B.

.
.
.
.
lock mutex2
.
.
.
try lock mutex1 ----> BLOCKED UNTIL THREAD A RELEASES LOCK!

线程A.

.
.
.
try lock mutex2 ---> BLOCKED UNTIL THREAD B RELEASES LOCK!

僵局!

读取这个 ,一些互斥体类型,如PTHREAD_MUTEX_NORMAL可能会导致线程自身死锁。

.
.
.
lock mutex
.
.
.
try lock

如果我写多个互斥锁会发生什么? 这两个互斥锁是否会被同一个线程选中?

线程可以同时保存任意数量的互斥锁。 在您的示例代码中,进入受Mutex1保护的区域的线程将尝试获取Mutex2 ,等待另一个线程在必要时首先释放它。 您提交的代码中没有特别的理由认为它不会成功。

我还读到多个互斥锁可能导致死锁。 任何人都可以解释我如何通过锁定部分代码与2个互斥锁导致死锁?

假设有两个线程,一个持有mutex1而另一个持有mutex2(在这种情况下,至少后者必须运行与你的伪代码不同的东西)。 现在假设每个线程都试图获取另一个互斥锁而不释放它已经拥有的互斥锁。 第一个线程必须获取mutex2才能继续,并且在另一个线程释放之前不能这样做。 第二个线程必须获取mutex1才能继续,并且在另一个线程释放之前不能这样做。 人机工程学, 两个线程不能继续-这是一个僵局。

一般规则是这样的:如果有一组互斥体,所有两个或多个线程可能都想要同时保持,那么每个线程在获取它们的任何子集时都必须遵循这些互斥体的固定相对排序。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM