• Python 36 死锁现象和递归锁、信号量、Event事件、线程queue


    一:死锁现象和递归锁

     所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁

    from threading import Thread,Lock,RLock
    import time
    
    # mutexA=Lock()
    # mutexB=Lock()
    mutexB=mutexA=RLock()
    
    
    class Mythead(Thread):
        def run(self):
            self.f1()
            self.f2()
    
        def f1(self):
            mutexA.acquire()
            print('%s 抢到A锁' %self.name)
            mutexB.acquire()
            print('%s 抢到B锁' %self.name)
            mutexB.release()
            mutexA.release()
    
        def f2(self):
            mutexB.acquire()
            print('%s 抢到了B锁' %self.name)
            time.sleep(2)
            mutexA.acquire()
            print('%s 抢到了A锁' %self.name)
            mutexA.release()
            mutexB.release()
    
    if __name__ == '__main__':
        for i in range(100):
            t=Mythead()
            t.start()
    View Code

    解决方法,递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。

    这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁:

    mutexA=mutexB=threading.RLock() #一个线程拿到锁,counter加1,该线程内又碰到加锁的情况,则counter继续加1,这期间所有其他线程都只能等待,等待该线程释放所有锁,即counter递减到0为止

    二:信号量

     Semaphore管理一个内置的计数器,
    每当调用acquire()时内置计数器-1;
    调用release() 时内置计数器+1;
    计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。

    from threading import Thread,Semaphore
    import time,random
    sm=Semaphore(5)
    
    def task(name):
        sm.acquire()
        print('%s 正在上厕所' %name)
        time.sleep(random.randint(1,3))
        sm.release()
    
    if __name__ == '__main__':
        for i in range(20):
            t=Thread(target=task,args=('路人%s' %i,))
            t.start()

    三:Event事件

     线程的一个关键特性是每个线程都是独立运行且状态不可预测。如果程序中的其 他线程需要通过判断某个线程的状态来确定自己下一步的操作,这时线程同步问题就会变得非常棘手。为了解决这些问题,我们需要使用threading库中的Event对象。 对象包含一个可由线程设置的信号标志,它允许线程等待某些事件的发生。在 初始情况下,Event对象中的信号标志被设置为假。如果有线程等待一个Event对象, 而这个Event对象的标志为假,那么这个线程将会被一直阻塞直至该标志为真。一个线程如果将一个Event对象的信号标志设置为真,它将唤醒所有等待这个Event对象的线程。如果一个线程等待一个已经被设置为真的Event对象,那么它将忽略这个事件, 继续执行

    event.isSet():返回event的状态值;
    
    event.wait():如果 event.isSet()==False将阻塞线程;
    
    event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
    
    event.clear():恢复event的状态值为False。
    import time
    
    event=Event()
    
    def light():
        print('红灯正亮着')
        time.sleep(3)
        event.set() #绿灯亮
    
    def car(name):
        print('车%s正在等绿灯' %name)
        event.wait() #等灯绿
        print('车%s通行' %name)
    
    if __name__ == '__main__':
        # 红绿灯
        t1=Thread(target=light)
        t1.start()
        #
        for i in range(10):
            t=Thread(target=car,args=(i,))
            t.start()

    四:线程queue

    class queue.Queue(maxsize=0) #先进先出

    import queue
    
    #先进先出
    queue.Queue() 
    q=queue.Queue(3)
    q.put(1)
    q.put(2)
    q.put(3)
    print(q.get())
    print(q.get())
    print(q.get())
    先进先出

     class queue.LifoQueue(maxsize=0) #last in fisrt out 

    import queue
    
    #后进先出->堆栈
    queue.LifoQueue()
    q=queue.LifoQueue(3)
    q.put(1)
    q.put(2)
    q.put(3)
    print(q.get())
    print(q.get())
    print(q.get())
    后进先出

     class queue.PriorityQueue(maxsize=0) #存储数据时可设置优先级的队列

    import queue
    
    #优先级,优先级用数字表示,数字越小优先级越高
    q=queue.PriorityQueue(3)
    q.put((10,'a'))
    q.put((-1,'b'))
    q.put((100,'c'))
    print(q.get())
    print(q.get())
    print(q.get())
    优先级
  • 相关阅读:
    Rehosting WWF 设计器
    C#写的ActiveX弹出窗口在Delphi程序中的应用时出现了问题。
    WWF的一些技术细节与应用体会(一)
    字符串编码与未公开的DBCSCodePageEncoding
    WF的一些技术细节与应用体会(三)
    Rehosting WWF Designer 之定制活动的外观
    WWF的一些技术细节与应用体会(二)
    DataJoin: Replicated join using DistributedCache
    MultipleOutputFormat和MultipleOutputs
    DataJoin: Reduceside join
  • 原文地址:https://www.cnblogs.com/zedong/p/9606688.html
Copyright © 2020-2023  润新知