• 死锁与递归锁


    死锁与递归锁

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

    死锁

    from threading import Thread,Lock,current_thread,RLock
    import time
    
    mutexA = Lock()
    mutexB = Lock()
    
    # mutexA = mutexB = RLock()
    
    class MyThread(Thread):
        def run(self):
            self.func1()
            self.func2()
    
        def func1(self):
            mutexA.acquire()
            print(f"{self.name}抢到了A锁")
            mutexB.acquire()
            print(f"{self.name}抢到了B锁")
            mutexB.release()
            print(f"{self.name}释放了B锁")
            mutexA.release()
            print(f"{self.name}释放了A锁")
    
        def func2(self):
            mutexB.acquire()
            print(f"{self.name}抢到了B锁")
            time.sleep(1)
            mutexA.acquire()
            print(f"{self.name}抢到了A锁")
            mutexA.release()
            print(f"{self.name}释放了A锁")
            mutexB.release()
            print(f"{self.name}释放了B锁")
    
    
    for i in range(10):
        t = MyThread()
        t.start()
        
    Thread-1抢到了A锁
    Thread-1抢到了B锁
    Thread-1释放了B锁
    Thread-1释放了A锁
    Thread-1抢到了B锁
    Thread-2抢到了A锁
    程序卡在这里,这就是死锁现象
    

    解决方法:递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。

    RLock可以提供被第一个抢到锁的人连续的acquire和release

    每acquire一次锁身上的计数加1

    每release一次锁身上的计数减1

    只要锁的计数不为0,其他人都不能抢。

    递归锁RLock

    from threading import Thread,Lock,current_thread,RLock
    import time
    
    # mutexA = Lock()
    # mutexB = Lock()
    
    mutexA = mutexB = RLock()  # A B 是用一把锁
    
    class MyThread(Thread):
        # 创建线程自动触发run方法,run方法内调用func1 func2相当于也是自动触发
        def run(self):
            self.func1()
            self.func2()
    
        def func1(self):
            mutexA.acquire()
            # self.name等价于current_thread().name
            print(f"{self.name}抢到了A锁")
            mutexB.acquire()
            print(f"{self.name}抢到了B锁")
            mutexB.release()
            print(f"{self.name}释放了B锁")
            mutexA.release()
            print(f"{self.name}释放了A锁")
    
        def func2(self):
            mutexB.acquire()
            print(f"{self.name}抢到了B锁")
            time.sleep(1)
            mutexA.acquire()
            print(f"{self.name}抢到了A锁")
            mutexA.release()
            print(f"{self.name}释放了A锁")
            mutexB.release()
            print(f"{self.name}释放了B锁")
    
    
    for i in range(10):
        t = MyThread()
        t.start()
    
    Thread-1抢到了A锁
    Thread-1抢到了B锁
    Thread-1释放了B锁
    Thread-1释放了A锁Thread-2抢到了A锁
    
    Thread-2抢到了B锁
    Thread-2释放了B锁
    Thread-2释放了A锁Thread-3抢到了A锁
    
    Thread-3抢到了B锁
    Thread-3释放了B锁
    Thread-3释放了A锁Thread-1抢到了B锁
    
    Thread-1抢到了A锁
    Thread-1释放了A锁
    Thread-1释放了B锁
    Thread-4抢到了A锁
    Thread-4抢到了B锁
    Thread-4释放了B锁
    Thread-4释放了A锁
    Thread-2抢到了B锁
    Thread-2抢到了A锁
    Thread-2释放了A锁
    Thread-2释放了B锁
    Thread-5抢到了A锁
    Thread-5抢到了B锁
    Thread-5释放了B锁
    Thread-5释放了A锁
    Thread-3抢到了B锁
    Thread-3抢到了A锁
    Thread-3释放了A锁
    Thread-3释放了B锁
    Thread-6抢到了A锁
    Thread-6抢到了B锁
    Thread-6释放了B锁
    Thread-6释放了A锁Thread-7抢到了A锁
    Thread-7抢到了B锁
    
    Thread-7释放了B锁
    Thread-7释放了A锁Thread-8抢到了A锁
    
    Thread-8抢到了B锁
    Thread-8释放了B锁
    Thread-8释放了A锁
    Thread-9抢到了A锁
    Thread-9抢到了B锁
    Thread-9释放了B锁
    Thread-9释放了A锁Thread-10抢到了A锁
    
    Thread-10抢到了B锁
    Thread-10释放了B锁
    Thread-10释放了A锁Thread-4抢到了B锁
    
    Thread-4抢到了A锁
    Thread-4释放了A锁
    Thread-4释放了B锁
    Thread-5抢到了B锁
    Thread-5抢到了A锁
    Thread-5释放了A锁
    Thread-5释放了B锁Thread-7抢到了B锁
    
    Thread-7抢到了A锁
    Thread-7释放了A锁
    Thread-7释放了B锁Thread-6抢到了B锁
    
    Thread-6抢到了A锁
    Thread-6释放了A锁
    Thread-6释放了B锁Thread-8抢到了B锁
    
    Thread-8抢到了A锁
    Thread-8释放了A锁
    Thread-8释放了B锁Thread-9抢到了B锁
    
    Thread-9抢到了A锁
    Thread-9释放了A锁
    Thread-9释放了B锁Thread-10抢到了B锁
    
    Thread-10抢到了A锁
    Thread-10释放了A锁
    Thread-10释放了B锁    
    

    只要类夹括号实例化对象,无论传入的参数是否一样生成的对象肯定不一样,单例模式除外。还有自己千万不要轻易的处理锁的问题。

    class Demo(object):
        pass
    obj1 = Demo()    
    obj2 = Demo()
    print(id(obj1),id(obj2))  # 41177456 41177424
    

    信号量

    信号量可能在不同的领域中,对应不同的知识点。

    互斥锁:一个厕所(一个坑位)

    信号量:公共厕所(多个坑位)

    0占了一个位置
    1占了一个位置
    2占了一个位置
    3占了一个位置
    4占了一个位置
    5占了一个位置
    6占了一个位置7占了一个位置
    
    9占了一个位置8占了一个位置
    
    10占了一个位置
    11占了一个位置
    12占了一个位置
    13占了一个位置
    14占了一个位置
    15占了一个位置
    16占了一个位置
    17占了一个位置
    18占了一个位置
    20占了一个位置
    19占了一个位置
    22占了一个位置21占了一个位置
    
    23占了一个位置24占了一个位置
    
    25占了一个位置
    26占了一个位置
    27占了一个位置
    28占了一个位置
    29占了一个位置
    30占了一个位置
    32占了一个位置31占了一个位置
    
    33占了一个位置
    34占了一个位置
    35占了一个位置
    36占了一个位置37占了一个位置
    
    38占了一个位置
    39占了一个位置
    

    event事件

    from threading import Event,Thread
    import time
    
    # 先生成一个event对象
    e = Event()
    
    def light():
        print("红灯正亮着")
        time.sleep(3)
        e.set()  # 发信号
        print("绿灯亮了")
    
    def car(name):
        print(f"{name}正在等红灯")
        e.wait()  # 等待信号
        print(f"{name}加油门飙车了")
    
    t = Thread(target=light)
    t.start()
    
    for i in range(10):
        t = Thread(target=car,args=(f"伞兵{i}",))
        t.start()
    
    红灯正亮着
    伞兵0正在等红灯
    伞兵1正在等红灯
    伞兵2正在等红灯
    伞兵3正在等红灯
    伞兵4正在等红灯
    伞兵5正在等红灯
    伞兵6正在等红灯
    伞兵7正在等红灯
    伞兵8正在等红灯
    伞兵9正在等红灯
    绿灯亮了伞兵0加油门飙车了
    伞兵1加油门飙车了
    伞兵5加油门飙车了
    伞兵6加油门飙车了伞兵8加油门飙车了
    伞兵9加油门飙车了
    伞兵2加油门飙车了
    
    伞兵4加油门飙车了伞兵7加油门飙车了
    伞兵3加油门飙车了    
    

    线程

    同一个进程下的多个线程本来就是数据共享,为什么还要用队列呢?

    因为队列是管道+锁 使用队列你就不需要自己手动操作锁的问题

    因为锁操作的不好极容易产生死锁现象。

    import queue
    
    
    q = queue.Queue()
    q.put("hahaha")
    print(q.get())
    
    # 后进先出
    q = queue.LifoQueue()
    q.put(1)
    q.put(2)
    q.put(3)
    print(q.get())  # 3
    
    
    # 优先级对列,数字越小,优先级越高
    q = queue.PriorityQueue()
    q.put((10,'hahaha'))
    q.put((100,"heheheh"))
    q.put((0,"xxx"))
    q.put((-10,"vvvv"))
    print(q.get())
    

    TCP使用线程实现并发效果

    # 客户端
    import socket
    
    client = socket.socket()
    client.connect(("127.0.0.1",8080))
    
    while True:
        client.send(b'hello')
        data = client.recv(1024)
        print(data.decode('utf-8'))
    
    # 服务端
    """
    服务端:
    	1.要有固定的IP和PORT
    	2.24小时不间断提供服务
    	3.能够支持并发
    """
    import socket
    from threading import Thread
    
    server = socket.socket()
    server.bind(("127.0.0.1",8080))
    server.listen(5)
    
    
    def talk(conn):
        while True:
            try:
                data = conn.recv(1024)
                if len(data) == 0:break
                print(data.decode('utf-8'))
                conn.send(data.upper())
            except ConnectionResetError as e:
                print(e)
                break
        conn.close()
    
    while True:
        # 等待客户端的连接 阻塞态
        conn,addr = server.accept()
        print(addr)
        t = Thread(target=talk,args=(conn,))
        t.start()
    
  • 相关阅读:
    [APIO2017] 商旅
    [SDOI2017] 新生舞会
    FileUtils类介绍
    经典算法面试题目-设计算法移除字符串中重复的字符(1.3)
    Web---演示Servlet的相关类、表单多参数接收、文件上传简单入门
    Java新手入门必须掌握的30个基本概念
    你需要知道的10位Java开发牛人
    Web---演示Servlet的相关类、下载技术、线程问题、自定义404页面
    经典算法面试题目-翻转一个C风格的字符串(1.2)
    Web---创建Servlet的3种方式、简单的用户注册功能
  • 原文地址:https://www.cnblogs.com/zuihoudebieli/p/11385101.html
Copyright © 2020-2023  润新知