zoukankan      html  css  js  c++  java
  • (13)线程---死锁,递归锁,互斥锁

     (1)线程之间虽然数据共享,但是多个线程同时修改同一份数据,依然会造成数据的不准确,因此,也需要加

    上线程锁Lock,用法和进程锁一样,只不过是从threading里面导包

    # (1)常见情况引发的死锁问题,模拟4个人吃一碗面
    
    from threading import Thread,Lock
    import time
    
    noodle_lock = Lock()
    kuaizi_lock = Lock()
    def eat1(name):
        noodle_lock.acquire()
        print("%s拿到这个面条" % (name))
        kuaizi_lock.acquire()
        print("%s拿到了筷子" % (name))
        print("开始吃")
        time.sleep(0.5)
        kuaizi_lock.release()
        print("%s把筷子放下"% (name))
        noodle_lock.release()
        print("%s把面放下"% (name))
    def eat2(name):
        kuaizi_lock.acquire()
        print("%s拿到了筷子" % (name))
        noodle_lock.acquire()
        print("%s拿到这个面条" % (name))
        print("开始吃")
        time.sleep(0.5)
        noodle_lock.release()
        print("%s把面放下"% (name))
        kuaizi_lock.release()
        print("%s把筷子放下"% (name))
    
    if __name__ == "__main__":
        name_list = ["张楠","定海呀"]
        name_list2 = ["晨露中","周金波"]
        for name in name_list:
            Thread(target=eat1,args= (name,) ).start()
        for name in name_list2:
            Thread(target=eat2,args = (name,)).start()
            
    View Code
    执行结果
    
    张楠拿到这个面条
    张楠拿到了筷子
    开始吃
    张楠把筷子放下
    晨露中拿到了筷子
    张楠把面放下定海呀拿到这个面条
    View Code

    运行完,发现这并不是我们想要的结果,一个人很难同时拿到面和筷子

    (2)不要因为逻辑问题让上锁分成两次.导致死锁,递归锁用于解决死锁,但只是一种应急的处理办法,关键

    时刻可以防止服务器崩溃,递归锁:RLock:递归所专门用来解决死锁现象的

    只要第一个进程拿到锁,该进程往下的锁全部打开,等他走完了,再放下一个进程进来

    from threading import Thread, RLock
    import time
    noodle_lock = kuaizi_lock = RLock()
    
    def eat1(name):
        noodle_lock.acquire()
        print("%s拿到这个面条" % (name))
        kuaizi_lock.acquire()
        print("%s拿到了筷子" % (name))
        print("开始吃")
        time.sleep(0.5)
        kuaizi_lock.release()
        print("%s把筷子放下" % (name))
        noodle_lock.release()
        print("%s把面放下" % (name))
    
    
    def eat2(name):
        kuaizi_lock.acquire()
        print("%s拿到了筷子" % (name))
        noodle_lock.acquire()
        print("%s拿到这个面条" % (name))
        print("开始吃")
        time.sleep(0.5)
        noodle_lock.release()
        print("%s把面放下" % (name))
        kuaizi_lock.release()
        print("%s把筷子放下" % (name))
    
    
    if __name__ == "__main__":
        name_list = ["张楠", "定海呀"]
        name_list2 = ["晨露中", "周金波"]
        for name in name_list:
            Thread(target=eat1, args=(name,)).start()
        for name in name_list2:
            Thread(target=eat2, args=(name,)).start()
    View Code
    张楠拿到这个面条
    张楠拿到了筷子
    开始吃
    张楠把筷子放下
    张楠把面放下
    定海呀拿到这个面条
    定海呀拿到了筷子
    开始吃
    定海呀把筷子放下
    定海呀把面放下
    晨露中拿到了筷子
    晨露中拿到这个面条
    开始吃
    晨露中把面放下
    周金波拿到了筷子
    周金波拿到这个面条
    开始吃
    晨露中把筷子放下
    周金波把面放下
    周金波把筷子放下
    View Code

    执行结果,会发现是不是基本完美了

    (3)从语法上说,锁是允许互相嵌套的,但是不要使用;

    上一次锁,就对应解开一次,形成互斥锁

    吃面和拿筷子是同时的,不要因为逻辑问题让锁分别上,容易造成死锁.

    from threading import Thread, Lock
    import time
    mylock = Lock()
    
    def eat1(name):
        mylock.acquire()
        print("%s拿到筷子" % (name))
        print("%s吃到面条" % (name))
        time.sleep(0.5)
    
        print("%s放下筷子" % (name))
        print("%s放下面条" % (name))
        mylock.release()
    
    def eat2(name):
        mylock.acquire()
        print("%s拿到筷子" % (name))
        print("%s吃到面条" % (name))
        time.sleep(0.5)
        print("%s放下筷子" % (name))
        print("%s放下面条" % (name))
        mylock.release()
    
    
    if __name__ == "__main__":
        name_list = ["张楠", "定海呀"]
        name_list2 = ["晨露中", "周金波"]
        for name in name_list:
            Thread(target=eat1, args=(name,)).start()
        for name in name_list2:
            Thread(target=eat2, args=(name,)).start()
    View Code
    张楠拿到筷子
    张楠吃到面条
    张楠放下筷子
    张楠放下面条
    定海呀拿到筷子
    定海呀吃到面条
    定海呀放下筷子
    定海呀放下面条
    晨露中拿到筷子
    晨露中吃到面条
    晨露中放下筷子
    晨露中放下面条
    周金波拿到筷子
    周金波吃到面条
    周金波放下筷子
    周金波放下面条
    View Code

    执行结果,这样写是不是看起来更清楚!

    (4)线程中的信号量Semaphore

    进程而言:

    信号量是配合Process使用,可以限制并发的进程数

    在有了进程池之后,可以取代如上做法

    线程而言:

    信号量是配合Thread使用的,可以限制并发的线程数

    线程池可以取代如上用法

    from threading import Semaphore,Thread
    import time
    start = time.time()
    def func(index,sem):
        sem.acquire()
        print(index)
        # time.sleep(1)
        sem.release()
    if __name__ == "__main__":
        sem = Semaphore(5)
        for i in range(16):
            Thread(target=func,args=(i,sem)).start()
        end = time.time()
        time_ = end - start
        print(time_)
    View Code
    执行结果:
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    0.0060002803802490234
    View Code

     

     

  • 相关阅读:
    给我30000出租车,还你一个不堵车的北京
    使用vim代替IDE
    (转)声明,函数与函数指针
    想恶作剧的请看过来
    bash命令提示符的更改
    (转)微软面试
    140个Google面试问题
    UTF8 GBK UTF8 GB2312 之间的区别和关系(转)
    MyBooksReadingStatic
    让SlickEdit 自动编译Keil C51工程
  • 原文地址:https://www.cnblogs.com/lyj910313/p/10787314.html
Copyright © 2011-2022 走看看