zoukankan      html  css  js  c++  java
  • 并发编程之线程死锁,递归锁 -2

    线程死锁,递归锁

      在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁,因为系统判断这部分资源都正在使用,所有这两个线程在无外力作用下将一直等待下去。

    import threading,time
    
    class myThread(threading.Thread):
        def doA(self):
            lockA.acquire()
            print(self.name,"gotlockA",time.ctime())
            time.sleep(3)
            lockB.acquire()
            print(self.name,"gotlockB",time.ctime())
            lockB.release()
            lockA.release()
    
        def doB(self):
            lockB.acquire()
            print(self.name,"gotlockB",time.ctime())
            time.sleep(2)
            lockA.acquire()
            print(self.name,"gotlockA",time.ctime())
            lockA.release()
            lockB.release()
    
        def run(self):
            self.doA()
            self.doB()
    if __name__=="__main__":
    
        lockA=threading.Lock()
        lockB=threading.Lock()
        threads=[]
        for i in range(5):
            threads.append(myThread())
        for t in threads:
            t.start()
        for t in threads:
            t.join()
    View Code

    应用

    import time
    
    import threading
    
    class Account:
        def __init__(self, _id, balance):
            self.id = _id
            self.balance = balance
            self.lock = threading.RLock()
    
        def withdraw(self, amount):
    
            with self.lock:
                self.balance -= amount
    
        def deposit(self, amount):
            with self.lock:
                self.balance += amount
    
    
        def drawcash(self, amount):#lock.acquire中嵌套lock.acquire的场景
    
            with self.lock:
                interest=0.05
                count=amount+amount*interest
    
                self.withdraw(count)
    
    
    def transfer(_from, to, amount):
    
        #锁不可以加在这里 因为其他的其它线程执行的其它方法在不加锁的情况下数据同样是不安全的
         _from.withdraw(amount)
    
         to.deposit(amount)
    
    
    
    tom = Account('tom',1000)
    jerry = Account('jerry',1000)
    
    t1=threading.Thread(target = transfer, args = (tom,jerry, 100))
    t1.start()
    
    t2=threading.Thread(target = transfer, args = (jerry,tom, 200))
    t2.start()
    
    t1.join()
    t2.join()
    
    print('>>>',tom.balance)
    print('>>>',jerry.balance)
    View Code

    同步条件(Event)

    import threading,time
    class Boss(threading.Thread):
        def run(self):
            print("BOSS:今晚大家都要加班到22:00。")
            print(event.isSet())
            event.set()
            time.sleep(5)
            print("BOSS:<22:00>可以下班了。")
            print(event.isSet())
            event.set()
    class Worker(threading.Thread):
        def run(self):
            event.wait()
            print("Worker:哎……命苦啊!")
            time.sleep(1)
            event.clear()
            event.wait()
            print("Worker:OhYeah!")
    if __name__=="__main__":
        event=threading.Event()
        threads=[]
        for i in range(5):
            threads.append(Worker())
        threads.append(Boss())
        for t in threads:
            t.start()
        for t in threads:
            t.join()
    View Code

    信号量(Semaphore) 

      信号量用来控制线程并发数的,BoundedSemaphore或Semaphore管理一个内置的计数 器,每当调用acquire()时-1,调用release()时+1。

          计数器不能小于0,当计数器为 0时,acquire()将阻塞线程至同步锁定状态,直到其他线程调用release()。(类似于停车位的概念)

          BoundedSemaphore与Semaphore的唯一区别在于前者将在调用release()时检查计数 器的值是否超过了计数器的初始值,如果超过了将抛出一个异常。

    import threading,time
    class myThread(threading.Thread):
        def run(self):
            if semaphore.acquire():
                print(self.name)
                time.sleep(5)
                semaphore.release()
    if __name__=="__main__":
        semaphore=threading.Semaphore(5)
        thrs=[]
        for i in range(100):
            thrs.append(myThread())
        for t in thrs:
            t.start()
    View Code

    列表是不安全的数据结构

    import threading,time
    
    li=[1,2,3,4,5]
    
    def pri():
        while li:
            a=li[-1]
            print(a)
            time.sleep(1)
            try:
                li.remove(a)
            except Exception as e:
                print('----',a,e)
    
    t1=threading.Thread(target=pri,args=())
    t1.start()
    t2=threading.Thread(target=pri,args=())
    t2.start()
    View Code

    queue列队类的方法

    创建一个“队列”对象
    import Queue
    q = Queue.Queue(maxsize = 10)
    Queue.Queue类即是一个队列的同步实现。队列长度可为无限或者有限。可通过Queue的构造函数的可选参数maxsize来设定队列长度。如果maxsize小于1就表示队列长度无限。
    
    将一个值放入队列中
    q.put(10)
    调用队列对象的put()方法在队尾插入一个项目。put()有两个参数,第一个item为必需的,为插入项目的值;第二个block为可选参数,默认为
    1。如果队列当前为空且block为1,put()方法就使调用线程暂停,直到空出一个数据单元。如果block为0,put方法将引发Full异常。
    
    将一个值从队列中取出
    q.get()
    调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block,默认为True。如果队列为空且block为True,
    get()就使调用线程暂停,直至有项目可用。如果队列为空且block为False,队列将引发Empty异常。
    
    Python Queue模块有三种队列及构造函数:
    1、Python Queue模块的FIFO队列先进先出。   class queue.Queue(maxsize)
    2、LIFO类似于堆,即先进后出。               class queue.LifoQueue(maxsize)
    3、还有一种是优先级队列级别越低越先出来。        class queue.PriorityQueue(maxsize)
    
    此包中的常用方法(q = Queue.Queue()):
    q.qsize() 返回队列的大小
    q.empty() 如果队列为空,返回True,反之False
    q.full() 如果队列满了,返回True,反之False
    q.full 与 maxsize 大小对应
    q.get([block[, timeout]]) 获取队列,timeout等待时间
    q.get_nowait() 相当q.get(False)
    非阻塞 q.put(item) 写入队列,timeout等待时间
    q.put_nowait(item) 相当q.put(item, False)
    q.task_done() 在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号
    q.join() 实际上意味着等到队列为空,再执行别的操作
    View Code
    import queue
    
    #先进后出
    
    q=queue.LifoQueue()
    
    q.put(34)
    q.put(56)
    q.put(12)
    
    #优先级
    # q=queue.PriorityQueue()
    # q.put([5,100])
    # q.put([7,200])
    # q.put([3,"hello"])
    # q.put([4,{"name":"alex"}])
    
    while 1:
    
      data=q.get()
      print(data)
    View Code

    生产者消费者模型:

    为什么要使用生产者和消费者模式

    在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。

    什么是生产者消费者模式

    生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

    这就像,在餐厅,厨师做好菜,不需要直接和客户交流,而是交给前台,而客户去饭菜也不需要不找厨师,直接去前台领取即可,这也是一个结耦的过程。

    import time,random
    import queue,threading
    
    q = queue.Queue()
    
    def Producer(name):
      count = 0
      while count <10:
        print("making........")
        time.sleep(random.randrange(3))
        q.put(count)
        print('Producer %s has produced %s baozi..' %(name, count))
        count +=1
        #q.task_done()
        #q.join()
        print("ok......")
    def Consumer(name):
      count = 0
      while count <10:
        time.sleep(random.randrange(4))
        if not q.empty():
            data = q.get()
            #q.task_done()
            #q.join()
            print(data)
            print('33[32;1mConsumer %s has eat %s baozi...33[0m' %(name, data))
        else:
            print("-----no baozi anymore----")
        count +=1
    
    p1 = threading.Thread(target=Producer, args=('A',))
    c1 = threading.Thread(target=Consumer, args=('B',))
    # c2 = threading.Thread(target=Consumer, args=('C',))
    # c3 = threading.Thread(target=Consumer, args=('D',))
    p1.start()
    c1.start()
    # c2.start()
    # c3.start()
    View Code
  • 相关阅读:
    用Processon在线绘制UML的尝试
    软工UML学习札记
    结对项目:计算器 第三篇
    结对项目:计算器 第二篇
    TXT四则运算计算器 后日谈
    TXT四则运算计算器
    软件工程作业 四则运算(一)
    敏捷开发
    如何做“足够好”的软件
    关于如何衡量个人在各自团队的效率和绩效
  • 原文地址:https://www.cnblogs.com/MR-allen/p/10518869.html
Copyright © 2011-2022 走看看