【问题标题】:Simulating a deadlock on a thread模拟线程上的死锁
【发布时间】:2013-01-11 22:59:26
【问题描述】:

我有 3 个线程,目前正在同时运行。

def f1():
    print "running first thread\n"
    sleep(10)

def f2():
    print "running second thread\n"
    sleep(10)

def f3():
    print "running third thread\n"
    sleep(10)


if __name__ == "__main__":
    thread1 = Thread(target = f1)
    thread2 = Thread(target = f2)
    thread3 = Thread(target = f3)

    try:
        thread1 = Thread(target = f1)
        thread1.start()

        thread2 = Thread(target = f2)
        thread2.start()

        thread3 = Thread(target = f3)   
        thread3.start()

        while(thread1.isAlive() or thread2.isAlive() or thread3.isAlive()): 
            thread1.join()
            thread2.join()
            thread3.join()  
    except (KeyboardInterrupt, SystemExit):
        sys.exit()

如何模拟死锁?另外,我怎样才能让每个线程一个接一个地运行?我还可以列出当前在我的脚本中运行的所有线程吗?还是给他们优先级?

【问题讨论】:

  • 您是在尝试模拟死锁(如标题所示),还是实际创建死锁(如正文所示)?而且,如果是后者,您只是想要一个在现实生活中永远不会出现的微不足道的人为死锁案例,还是有点现实场景的最简单示例?
  • 对于初学者,您可能想要一个可以在某处死锁的锁:effbot.org/zone/thread-synchronization.htm
  • @abarnert;我实际上需要模拟一个死锁,抱歉我编辑了我的帖子。
  • @paulsm4:嗯,你可以使用线程本身。例如,只需在f1 中执行thread2.join() 和在f2 中执行thread1.join(),就会死锁。

标签: python process deadlock


【解决方案1】:

如何模拟死锁?

所有的死锁意味着一个或多个线程被阻止取得任何进展,所以你可以用一个线程来模拟它。只需在sleep(10) 周围加上while True:

在实际情况下,您通常有两个线程同时阻止彼此的进程。例如,也许他们以相反的顺序获取了一对锁,所以线程 1 在获得锁 2 之前不会释放锁 1,但线程 2 在获得锁 1 之前不会释放锁 2。所以,它可能最好让两个线程永久阻塞来模拟它。

如果您想实际创建死锁,最简单的方法是让线程相互阻塞:将thread2.join() 添加到f1,并将thread1.join() 添加到f2。然后f1 直到f2 完成,f2 才能完成直到f1 完成,所以没有人可以完成。

但是,如果您想创建一个真实的死锁,您几乎肯定会想要使用像 threading.Lock 这样的同步对象来执行类似于上述两锁场景的操作。

另外,我怎样才能让每个线程一个接一个地运行?

嗯,最简单的方法是一开始就不使用线程。但如果你真的想要,就这样做吧:

thread1.start()
thread1.join()
thread2.start()
thread2.join()
thread3.start()
thread3.join()

我还可以列出当前在我的脚本中运行的所有线程吗?

threading.enumerate()。除了调试目的,您通常不想使用它;在创建线程时跟踪它们,如果您想稍后访问它们(就像您正在做的那样)。

还是给他们优先级?

正如文档所说:

目前没有优先级,没有线程组,线程不能被销毁、停止、挂起、恢复或中断。

如果你想这样做,你必须跳出threading,例如,通过ctypeswin32api等使用本机API。

【讨论】:

    【解决方案2】:

    如何模拟死锁?

    import threading
    import time
    
    l1=threading.Lock()
    l2 = threading.Lock()
    
    def f1(name):
        print('thread',name,'about to lock l1')
        with l1:
            print('thread',name,'has lock l1')
            time.sleep(0.3)
            print('thread',name,'about to lock l2')
            with l2:
                print('thread',name,'run into deadLock,\nthis line will never run')
    
    def f2(name):
        print('thread',name,'about to lock l2')
        with l2:
            print('thread',name,'has lock l2')
            time.sleep(0.3)
            print('thread',name,'about to lock l1')
            with l1:
                print('thread',name,'run into deadLock,\nthis line will never run')
    
    if __name__ == '__main__':
        t1=threading.Thread(target=f1, args=['t1',])
        t2=threading.Thread(target=f2, args=['t2',])
    
        t1.start()
        t2.start()
    

    输出:

    $ python tmpThread.py
    thread t1 about to lock l1
    thread t2 about to lock l2
    thread t1 has lock l1
    thread t2 has lock l2
    thread t1 about to lock l2
    thread t2 about to lock l1
    

    【讨论】:

    • 好答案,但函数 f2 的第二个 'with' 有错字,它必须是 'with l1'
    【解决方案3】:

    经典的银行转账死锁示例。

    from threading import Lock, Thread
    
    accountone = Lock()
    accounttwo = Lock()
    
    def transfer(accountone, accounttwo):
        accountone.acquire()
        accounttwo.acquire()
        print("Transaction done")
        accountone.release()
        accounttwo.release()
    
    def transfer_do(accountone, accounttwo):
        while True:
            transfer(accountone, accounttwo) # send money from first account to second
            transfer(accounttwo, accountone) # send money from second account to first
    
    for x in range(30):
        t = Thread(target=transfer_do, args=(accountone, accounttwo))
        t.start()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-22
      • 2010-09-10
      • 2018-06-16
      • 2016-04-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多