如何理解相同类的实例会导致C++ Concurrency in Action中的死锁问题?
我读C++ Concurrency in Action,并遇到了下面的语句,描述deadlock
(第47〜48):如何理解相同类的实例会导致C++ Concurrency in Action中的死锁问题?
避免死锁的共同建议是始终锁定两个互斥在同一顺序:如果你总是在互斥体B之前锁定互斥体A,那么你将永远不会死锁。有时候这很简单,因为互斥对象服务于不同的目的,但有时并不那么简单,比如当互斥对象保护同一个类的单独实例时。例如,考虑在同一类的两个实例之间交换数据的操作;为了确保数据正确交换,不受并发修改的影响,两个实例上的互斥锁都必须锁定。但是,如果选择了一个固定的顺序(例如,作为第一个参数提供的实例的互斥体,然后是作为第二个参数提供的实例的互斥体),则这可能会逆流:它只需要两个线程尝试在交换参数的同一两个实例之间交换数据,并且您有死锁!
我对以下部分的含义很困惑:
然而,如果以固定的顺序被选择(例如,互斥为作为第一个参数提供的实例,则互斥为作为第二个参数提供的实例),这可能会逆火:它只需要两个线程尝试在交换参数的同一个两个实例之间交换数据,并且发生死锁!
在前面,它指的是“an operation
”,然后它提到了“two threads to try to exchange data
”。作者想要表达的实际场景是什么?
这是指这样的情况:
你有一个函数
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);
在另一个
。那么,你有一个僵局。
交换操作是可交换的,因此您不能保证算法将以相同的参数顺序执行此操作。因此,如果有对象a
和b
,则一个线程可以执行Swap(a, b)
,而另一个Swap(b, a)
和最终结果锁按默认顺序不同。
如果时机不好,这将导致死锁。
请注意,这可以更强制三个对象和三个线程:Swap(a, b)
,Swap(b, c)
,Swap(c, a)
。在这里锁定第一个参数而不是第二个参数也会导致死锁。
在以前,它是指“操作”,然后将其提到了“两个线程试图交换数据”
你错过了句子的结尾!它说“两个线程尝试在相同的两个实例之间交换数据”。它并不是讨论线程之间交换数据,而是讨论一个线程在一个类型的两个实例之间交换数据,以及另一个线程在相同的两个实例之间交换数据。