zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    linux usb 驱动详解
    md5sum.c, md5.c, md5.h
    安装 Kali Linux 后需要做的 20 件事
    Readprocessmemory使用方法
    在Centos下安装matlab
    PE文件简单介绍
    MATLAB中导入数据:importdata函数
    数据交换工具Kettle
    编写你自己的单点登录(SSO)服务
    AVL树
  • 原文地址:https://www.cnblogs.com/znyyy/p/10175155.html
Copyright © 2011-2022 走看看