multithreading - 如果可以动态获取锁,则强加锁顺序并不能保证防止死锁。这是什么意思?

标签 multithreading operating-system deadlock

无法理解以下摘自 Galvin 第 9 版第 7 章死锁页 326 的文字。

如果可以动态获取锁,则强加锁顺序并不能保证防止死锁。例如,假设我们有一个在两个账户之间转移资金的功能。为了防止竞争条件,每个帐户都有一个关联的互斥锁,该互斥锁是从 get lock() 函数获得的,如以下程序所示:

void transaction(Account from, Account to, double amount)
{ 
       mutex lock1, lock2; 
       lock1 = get lock(from); 
       lock2 = get lock(to);

       acquire(lock1);
          acquire(lock2);
            withdraw(from, amount);
            deposit(to, amount);
          release(lock2);
       release(lock1);
}

如果两个线程同时调用 transaction() 函数,调换不同的帐户,则可能会出现死锁。也就是说,一个线程可能调用

transaction(checking account, savings account, 25);

另一个可能调用

transaction(savings account, checking account, 50);

谁能帮我理解这里的意思?

最佳答案

作者太懒了。所有文本真正告诉您的是,如果您不强加严格的锁定顺序,强加严格的锁定顺序将无济于事。

示例中的代码没有强加任何锁定顺序,因为它以参数传入的顺序锁定锁。想象一下如果有两个并发调用会发生什么情况:一个线程调用 transaction(A, B) 同时,另一个线程调用 transaction(B, A)。这两个线程将各自尝试以彼此相反的顺序锁定相同的两个锁。这是导致死锁的经典秘诀。


修复示例以使其确实强加严格顺序的方法是明确锁定顺序。

void transaction(Account from, Account to, double amount)
{ 
    mutex lock1, lock2;
    if (from.getAccountNumber() < to.getAccountNumber()) {        
        lock1 = from.getLock(); 
        lock2 = to.getLock();
    } else {
        lock1 = to.getLock(); 
        lock2 = from.getLock();
    }

    acquire(lock1);
    acquire(lock2);
    withdraw(from, amount);
    deposit(to, amount);
    release(lock2);
    release(lock1);
}

关于multithreading - 如果可以动态获取锁,则强加锁顺序并不能保证防止死锁。这是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46068630/

相关文章:

python - 为什么线程比子进程慢?我什么时候应该使用子进程代替线程,反之亦然

c - 如何为数据采集硬件实现 Linux 设备驱动程序?

operating-system - 启用 GRUB 从内核自动引导

sql-server - 解释死锁并修复它

c# - 获取异步结果死锁(尽管将 configure await 设置为 false)

c# - 如何以随机间隔将执行挂起一段随机时间

java - 释放 "synchronized"锁

java - Java中创建新线程有多少种方式?

单个管道是否可以被多个进程连接和读取

mysql - Innodb 死锁,看起来像 tx 锁本身