(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

 

 

 

posted @ 2019-04-28 22:19  夜雨潇湘子  阅读(144)  评论(0编辑  收藏  举报