7

单线程应用程序会出现死锁吗?如果有,请举个例子。

4

5 回答 5

9

是的,如果您拥有不可重入的锁并且线程尝试重新获取它已经拥有的锁(例如通过递归调用),则单线程应用程序可能会死锁。

编辑:我看到帖子被标记为“Java”;我不知道这是更新还是我之前错过了它,但无论如何,Java 中的锁都是可重入的,因此您将无法以这种方式死锁单线程应用程序。

于 2010-01-29T15:33:02.597 回答
7

是的,如果应用程序与另一个应用程序共享资源,它可能会死锁。

于 2010-01-29T15:36:20.843 回答
5

这在一定程度上取决于您如何解释这个问题。如果涉及与其他应用程序共享的资源,则可以。没有共享资源,没有。

死锁是一种情况,其中两个或多个竞争动作正在等待另一个完成,因此永远不会。

单线程,只有一个动作,无法与自己竞争。

来自维基百科:

必要条件

发生死锁有四个必要和充分条件,即 EG Coffman 在 1971 年的一篇文章中首次描述的 Coffman 条件。

  1. 互斥条件:一次不能被多个进程使用的资源
  2. 持有和等待条件:已经持有资源的进程可能会请求新的资源
  3. 无抢占条件:任何资源都不能从持有它的进程中强制移除,资源只能通过进程的显式动作释放
  4. 循环等待条件:两个或多个进程形成一个循环链,其中每个进程等待链中下一个进程持有的资源

根据这个定义,需要两个进程来构成死锁。

于 2010-01-29T15:35:45.707 回答
1

线程 A 获取资源 1,并尝试重新获取资源 1。自循环情况。

线程获取 lock1 -> 在临界区运行 -> 尝试获取 lock1 -> 无限等待 == 自死锁。为了解决这个问题,你需要递归锁。

于 2013-03-02T22:44:28.710 回答
1

是的,单线程事件驱动(非阻塞)应用程序肯定会死锁。即使没有任何操作系统同步原语,如互斥锁,甚至根本没有操作系统。在 FSM(有限状态机)设计中,死锁是常见的错误。

假设您有一个只能通过 write(COMMAND) 然后 read(RESP) 模式访问的串行设备。所以要同时访问它你需要一些序列化技术。最简单的方法是排队。这是 Javascript 中此类队列的最简单实现:

function SharedResource() {
    var self = {
        queue_: [],
        
        acquire: function(on_sharedResource_ready) {
            var n = self.queue_.push(on_sharedResource_ready);
            if(n==1){ // first task
                on_sharedResource_ready();
            }
        },
    
        release: function() {
            if(self.queue_.length >= 1) {
                // Pop current task
                self.queue_.shift();
                
                // Exec the next task
                var next = self.queue_[0];
                if(next) {
                    next();
                }
            }else{
                throw 'SharedResource::release(): BUG - queue is empty';
            }
        },
    };
    
    return self;
}

我们可以在 button_click 事件中使用它,例如:

var serialPort1 = SharedResource();
var serialPort2 = SharedResource();

function button1_on_click(){
    log("button1_on_click(): Acquiring serial port 1");
    serialPort1.acquire(function(){
        log("button1 Serial port 1 acquired");
        setTimeout(function(){
            log("button1: Acquiring serial port 2");
            serialPort2.acquire(function(){
                log("button1 Serial port 2 acquired");
                // Simulate long time work with a ports
                setTimeout(on_work_with_serial_port_done, 2000);
            });
        }, 1000);
    });
    
    function on_work_with_serial_port_done(){
        log("button1 Releasing serial port 2");
        serialPort2.release();
        log("button1 Releasing serial port 1");
        serialPort1.release();
    }
}

function button2_on_click(){
    log("button2_on_click(): Acquiring serial port 2");
    serialPort2.acquire(function(){
        log("button2 Serial port 2 acquired");
        setTimeout(function(){
            log("button2: Acquiring serial port 1");
            serialPort1.acquire(function(){
                log("button2 Serial port 1 acquired");
                // Simulate long time work with a ports
                setTimeout(on_work_with_serial_port_done, 2000);
            });
        }, 1000);
    });
    
    function on_work_with_serial_port_done(){
        log("button2 Releasing serial port 1");
        serialPort1.release();
        log("button2 Releasing serial port 2");
        serialPort2.release();
    }
}

其余的代码让它工作:

function getTime(){
    var today = new Date();
    var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
    return time;
}

// simple logger
function log(text){
    var logdiv = document.getElementById('log');
    var br = document.createElement("br");
    var t = document.createTextNode(getTime()+ ": " + text);
    logdiv.appendChild(t);
    logdiv.appendChild(br);
}

// register event handlers
window.onload = function () {
    var btn1 = document.getElementById('button1');
    btn1.onclick = button1_on_click;
    
    var btn2 = document.getElementById('button2');
    btn2.onclick = button2_on_click;
};

<html><head><script src="deadlock.js"></script></head><body>
<input type="button" value="Do work1" id="button1">
<input type="button" value="Do work2" id="button2">
<div id="log"></div>
</body></html>

如果我们按下按钮 1 并在超过 1 秒后按下按钮 2 一切都会正常工作:

16:12:20: button1_on_click(): Acquiring serial port 1
16:12:20: button1 Serial port 1 acquired
16:12:21: button1: Acquiring serial port 2
16:12:21: button1 Serial port 2 acquired
16:12:21: button2_on_click(): Acquiring serial port 2
16:12:23: button1 Releasing serial port 2
16:12:23: button2 Serial port 2 acquired
16:12:23: button1 Releasing serial port 1
16:12:24: button2: Acquiring serial port 1
16:12:24: button2 Serial port 1 acquired
16:12:26: button2 Releasing serial port 1
16:12:26: button2 Releasing serial port 2

但是如果我们快速按下按钮 1 然后按钮 2应用程序将死锁并且不会再响应按钮 1 和按钮 2 的点击

16:14:28: button1_on_click(): Acquiring serial port 1
16:14:28: button1 Serial port 1 acquired
16:14:28: button2_on_click(): Acquiring serial port 2
16:14:28: button2 Serial port 2 acquired
16:14:29: button1: Acquiring serial port 2
16:14:29: button2: Acquiring serial port 1
16:14:41: button1_on_click(): Acquiring serial port 1
16:14:41: button2_on_click(): Acquiring serial port 2
16:14:41: button1_on_click(): Acquiring serial port 1
16:14:42: button2_on_click(): Acquiring serial port 2
16:14:42: button1_on_click(): Acquiring serial port 1
16:14:42: button2_on_click(): Acquiring serial port 2
16:14:45: button2_on_click(): Acquiring serial port 2
16:14:45: button2_on_click(): Acquiring serial port 2
16:14:46: button1_on_click(): Acquiring serial port 1
16:14:46: button1_on_click(): Acquiring serial port 1
16:14:47: button1_on_click(): Acquiring serial port 1

当然,我们的应用程序仍然可以处理其他事件,例如 button3。在多线程应用中情况完全一样——当thread1和thread2相互死锁时,thread3仍然可以工作。

于 2021-07-20T13:05:30.213 回答