2017-10-19 157 views
0

我读C++ Concurrency in Action,并遇到了下面的语句,描述deadlock(第47〜48):如何理解相同类的实例会导致C++ Concurrency in Action中的死锁问题?

避免死锁的共同建议是始终锁定两个互斥在同一顺序:如果你总是在互斥体B之前锁定互斥体A,那么你将永远不会死锁。有时候这很简单,因为互斥对象服务于不同的目的,但有时并不那么简单,比如当互斥对象保护同一个类的单独实例时。例如,考虑在同一类的两个实例之间交换数据的操作;为了确保数据正确交换,不受并发修改的影响,两个实例上的互斥锁都必须锁定。但是,如果选择了一个固定的顺序(例如,作为第一个参数提供的实例的互斥体,然后是作为第二个参数提供的实例的互斥体),则这可能会逆流:它只需要两个线程尝试在交换参数的同一两个实例之间交换数据,并且您有死锁!

我对以下部分的含义很困惑:

然而,如果以固定的顺序被选择(例如,互斥为作为第一个参数提供的实例,则互斥为作为第二个参数提供的实例),这可能会逆火:它只需要两个线程尝试在交换参数的同一个两个实例之间交换数据,并且发生死锁!

在前面,它指的是“an operation”,然后它提到了“two threads to try to exchange data”。作者想要表达的实际场景是什么?

回答

1

这是指这样的情况:

你有一个函数

void foo(bar& a, bar& b) { 
    lock_guard<mutex> lock1(a.mutex); 
    ... 
    lock_guard<mutex> lock2(b.mutex); 
} 

其中,乍一看,似乎遵循的总是以相同的顺序锁定互斥的咨询。

但如果你有

bar a, b; 

foo可以在一个线程被称为

foo(a, b); 

,并作为

foo(b, a); 
在另一个

。那么,你有一个僵局。

0

交换操作是可交换的,因此您不能保证算法将以相同的参数顺序执行此操作。因此,如果有对象ab,则一个线程可以执行Swap(a, b),而另一个Swap(b, a)和最终结果锁按默认顺序不同。

如果时机不好,这将导致死锁。

请注意,这可以更强制三个对象和三个线程:Swap(a, b)Swap(b, c)Swap(c, a)。在这里锁定第一个参数而不是第二个参数也会导致死锁。

1

在以前,它是指“操作”,然后将其提到了“两个线程试图交换数据”

你错过了句子的结尾!它说“两个线程尝试在相同的两个实例之间交换数据”。它并不是讨论线程之间交换数据,而是讨论一个线程在一个类型的两个实例之间交换数据,以及另一个线程在相同的两个实例之间交换数据。