在以下代码中,如果两个线程同时调用transaction()
函数,转置不同的帐户,则可能出现死锁。
void transaction(Account from, Account to, double amount)
{
mutex lock1, lock2;
lock1 = getlock(from);
lock2 = getlock(to);
acquire(lock1);
acquire(lock2);
withdraw(from, amount);
deposit(to, amount);
release(lock2);
release(lock1);
}
也就是说,一个线程可能会调用
transaction(checkingaccount, savingsaccount, 25);
,另一个可能会调用
transaction(savingsaccount, checkingaccount, 50);
这个问题的解决方案是什么?
我能想到的是使用见证程序来警告用户发生了死锁,但必须有一个更好的解决方案,可以通过修改代码来实现。有什么想法吗?
PS:这是来自操作系统的教科书。这不是功课,只是关于僵局的章节的一部分。
答案 0 :(得分:2)
这是Java Concurrency in Practice中描述的问题(连同解决方案一起),即项目 10.1.2动态锁定顺序死锁,该问题专门针对Java编写,但是逻辑可以很好应用于其他环境(例如您的环境)。
因此,由于我们无法控制参数的提供顺序,因此我们需要在锁上推导顺序,并根据整个程序中一致的诱导顺序来获取它们写作。
一种引发该顺序的方法是计算from
和to
对象的哈希码,然后首先使用较低的哈希码从该对象获取锁进行同步。在(罕见的)情况下,两个Account
对象具有相同的哈希码,我们将需要引入第三个锁来“打破”领带。
例如在Java中,它将是:
int fromHash = System.identityHashCode(from);
int toHash = System.identityHashCode(to);
现在,以您的代码作为参考,它可能类似于以下代码。
Object objectForTieBreakerLock = new Object(); // a valid new object here according to your language
void transaction(Account from, Account to, double amount)
{
mutex lock1, lock2, tieBreaker;
lock1 = getlock(from);
lock2 = getlock(to);
int fromHash = /*any language specific function to get object hash*/;
int toHash = /*any language specific function to get object hash*/;
if (fromHash < toHash) {
acquire(lock1);
acquire(lock2);
doTransaction(from, to, amount);
release(lock2);
release(lock1);
}
else if (fromHash > toHash) {
acquire(lock2);
acquire(lock1);
doTransaction(from, to, amount);
release(lock1);
release(lock2);
}
else {
tieBreaker = getlock(objectForTieBreakerLock);
acquire(tieBreaker);
acquire(lock1);
acquire(lock2);
doTransaction(from, to, amount);
release(lock2);
release(lock1);
release(tieBreaker);
}
}
// this must be a private (helper) method
void doTransaction(Account from, Account to, double amount)
{
withdraw(from, amount);
deposit(to, amount);
}
附加说明
如果Account
具有唯一的,不可变的,可比较的键,例如唯一的数字,标识符或类似的东西,则诱导锁排序将更容易:通过对象的键对对象进行排序,从而消除这种情况tieBreaker
锁定的方式。
完整的Java代码示例:http://jcip.net/listings/InduceLockOrder.java