Python3 从零单排27_锁&信号量&Event&定时器

  1.死锁

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

 1 from threading import Thread,Lock
 2 import time
 3 
 4 mutexA=Lock()
 5 mutexB=Lock()
 6 
 7 class MyThread(Thread):
 8     def run(self):
 9         self.f1()
10         self.f2()
11 
12     def f1(self):
13         mutexA.acquire()
14         print('%s 拿到了A锁' % self.name)
15         mutexB.acquire()
16         print('%s 拿到了B锁' % self.name)
17         mutexB.release()
18         print('%s 释放了B锁' % self.name)
19         mutexA.release()
20         print('%s 释放了A锁' % self.name)
21 
22     def f2(self):
23         mutexB.acquire()
24         print('%s 拿到了B锁' % self.name)
25         time.sleep(0.1)
26         mutexA.acquire()
27         print('%s 拿到了A锁' % self.name)
28         mutexA.release()
29         print('%s 释放了A锁' % self.name)
30         mutexB.release()
31         print('%s 释放了B锁' % self.name)
32 
33 if __name__ == '__main__':
34     for i in range(10):
35         t=MyThread()
36         t.start()
View Code

  2.递归锁

  互斥锁只能acquire一次

  递归锁:可以连续acquire多次,每acquire一次计数器+1,只有计数为0时,才能被抢到acquire

 1 # 互斥锁只能acquire一次
 2 from threading import Thread,Lock
 3 
 4 mutexA=Lock()
 5 
 6 mutexA.acquire()
 7 mutexA.acquire()  # 程序卡在这里了
 8 
 9 
10 # 递归锁:可以连续acquire多次,每acquire一次计数器+1,只有计数为0时,才能被抢到acquire
11 from threading import Thread,RLock
12 import time
13 
14 mutexB=mutexA=RLock()
15 
16 class MyThread(Thread):
17     def run(self):
18         self.f1()
19         self.f2()
20 
21     def f1(self):
22         mutexA.acquire()
23         print('%s 拿到了A锁' % self.name)
24         mutexB.acquire()
25         print('%s 拿到了B锁' % self.name)
26         mutexB.release()
27         print('%s 释放了B锁' % self.name)
28         mutexA.release()
29         print('%s 释放了A锁' % self.name)
30 
31     def f2(self):
32         mutexB.acquire()
33         print('%s 拿到了B锁' % self.name)
34         time.sleep(0.1)
35         mutexA.acquire()
36         print('%s 拿到了A锁' % self.name)
37         mutexA.release()
38         print('%s 释放了A锁' % self.name)
39         mutexB.release()
40         print('%s 释放了B锁' % self.name)
41 
42 if __name__ == '__main__':
43     for i in range(10):
44         t=MyThread()
45         t.start()
View Code

  3.信号量

  互斥锁或者递归锁都只能在一个时间点为同一个线程服务,一个萝卜一个坑。但是多个萝卜可以同时占用多个坑就没办法了,这里就用到了信号量。
  信号量,体现在量,批量,也就是说支持同一时间点可以给多个线程用,原理实际是计数器,占用一个-1,释放一个+1,计数不能小于0。
  Semaphore管理一个内置的计数器,每当调用acquire()时内置计数器-1;调用release() 时内置计数器+1;
  计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。

 1 from threading import Thread, Semaphore, current_thread
 2 import time, random
 3 se = Semaphore(3)  # 最多只能同时占用3次
 4 
 5 
 6 def toilet():
 7     with se:  # 用法同文件操作,将打开和关闭合并在with语法里。  等价于  se.acquire()  se.release()
 8         print("%s go in" % current_thread().getName())
 9         time.sleep(random.randint(1, 3))
10 
11 
12 if __name__ == "__main__":
13     for i in range(10):
14         t = Thread(target=toilet)
15         t.start()
View Code

  4.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。

 1 from threading import Thread, Event
 2 import time
 3 e = Event()
 4 
 5 def student(name):
 6     print("%s is learning" % name)
 7     e.wait(3)  # 一直等event.set(),最多等3秒
 8     print("%s is playing" % name)
 9 
10 def teacher(name):
11     print("%s is teaching" % name)
12     time.sleep(6)
13     print("%s said class over!" % name)
14     e.set()
15 
16 
17 if __name__ == "__main__":
18     for i in range(10):
19         s = Thread(target=student, args=(i,))
20         s.start()
21     t = Thread(target=teacher)
22     t.start()
View Code

  5.定时器  定时执行任务

 1 from threading import Timer
 2 
 3 
 4 def toilet(name):
 5     print("%s go in" % name)
 6 
 7 
 8 if __name__ == "__main__":
 9     for i in range(10):
10         t = Timer(3, toilet, args=("xg %s" % i,))  # 3秒后 启动toilet
11         t.start()
12 
13 
14 from threading import Timer
15 import random
16 
17 class Code:
18     def __init__(self):
19         self.make_cache()
20 
21     def make_cache(self,interval=5):
22         self.cache=self.make_code()
23         print(self.cache)
24         self.t=Timer(interval,self.make_cache)
25         self.t.start()
26 
27     def make_code(self,n=4):
28         res=''
29         for i in range(n):
30             s1=str(random.randint(0,9))
31             s2=chr(random.randint(65,90))
32             res+=random.choice([s1,s2])
33         return res
34 
35     def check(self):
36         while True:
37             code=input('请输入你的验证码>>: ').strip()
38             if code.upper() == self.cache:
39                 print('验证码输入正确')
40                 self.t.cancel()
41                 break
42 
43 
44 obj=Code()
45 obj.check()
View Code
原文地址:https://www.cnblogs.com/znyyy/p/10175155.html