首页 > 其他分享 >三把锁和event事件

三把锁和event事件

时间:2024-01-20 18:45:00浏览次数:16  
标签:__ task Thread 车位 抢到 事件 线程 event

死锁和递归锁

【1】死锁

def task(i):
    mutex_1.acquire()
    print(f'{current_thread().name}抢到了第一把锁')
    mutex_2.acquire()
    print(f'{current_thread().name}抢到了第二把锁')
    mutex_2.release()  # 释放锁二
    mutex_1.release()  # 释放锁一


    mutex_2.acquire()
    print(f'{current_thread().name}抢到了第二把锁')
    mutex_1.acquire()
    time.sleep(1)
    print(f'{current_thread().name}抢到了第一把锁')
    mutex_1.release()  # 释放锁一
    mutex_2.release()  # 释放锁二


if __name__ == '__main__':
    t_list = [Thread(target=task, args=(i,)) for i in range(1, 8)]
    for t in t_list:
        t.start()
  • 在这个例子中,我添加了两把锁(锁1,锁2),创建多个线程去抢锁
  • 仔细看这个例子,会发现这是个死锁
  1. 线程1拿到锁1
  2. 其他线程会被堵住,因为线程1没有释放锁1
  3. 线程1拿到锁2
  4. 其他线程会被堵住,因为线程1没有释放锁1
  5. 线程1释放锁2
  6. 其他线程会被堵住,因为线程1没有释放锁1
  7. 线程1释放锁1
  8. 其他线程会争夺锁1
  9. 线程1拿到锁2
  10. 拿到锁1的线程不会释放锁1,因为他没有拿到锁2
  11. 线程1不会拿到锁1,其他程序没有释放锁1
  12. 程序夯住,这就是死锁线程

【2】递归锁

  • 递归锁(Recursive Lock)是一种特殊类型的锁,它允许同一个线程多次获取同一资源的锁定。在多线程环境中,当一个线程已经持有某个锁时,如果它再次尝试获取同一个锁,通常情况下会导致死锁。但如果这个锁是递归锁,线程可以再次获得锁而不会阻塞。
  • 递归锁内部维护了一个计数器和一个原始所有者线程的标识。当线程首次获取锁时,计数器会增加,锁的所有者被设置为当前线程。如果同一个线程再次获取锁,计数器会继续增加。每次线程释放锁时,计数器减一。只有当计数器回到零时,锁才会真正释放,其他线程才能获取它。
  • 递归锁在 Python 中可以通过 threading 模块中的 RLock 类实现。
from threading import Thread, RLock, current_thread

mutex = RLock()


def task(i):
    mutex.acquire()
    print(f'{current_thread().name}抢到了锁')
    mutex.acquire()
    print(f'{current_thread().name}抢到了锁')
    mutex.release()
    mutex.release()


if __name__ == '__main__':
    t_list = [Thread(target=task, args=(i,)) for i in range(1, 11)]
    for t in t_list:
        t.start()
'''
Thread-1 (task)抢到了锁
Thread-1 (task)抢到了锁
Thread-2 (task)抢到了锁
Thread-2 (task)抢到了锁
Thread-3 (task)抢到了锁
Thread-3 (task)抢到了锁
Thread-4 (task)抢到了锁
Thread-4 (task)抢到了锁
Thread-5 (task)抢到了锁
Thread-5 (task)抢到了锁
Thread-6 (task)抢到了锁
Thread-6 (task)抢到了锁
Thread-7 (task)抢到了锁
Thread-7 (task)抢到了锁
Thread-8 (task)抢到了锁
Thread-8 (task)抢到了锁
Thread-9 (task)抢到了锁
Thread-9 (task)抢到了锁
Thread-10 (task)抢到了锁
Thread-10 (task)抢到了锁

进程已结束,退出代码0

'''

【3】信号量

  • 计数器: 信号量内部维护了一个计数器,这个计数器表示可用的资源数量。当计数器大于零时,表示有资源可用;当计数器为零时,表示没有可用资源。

  • 获取(Acquire)操作: 当一个线程尝试获取信号量时,如果计数器大于零,计数器就减一,线程获得资源的访问权限。如果计数器为零,线程会被阻塞,直到计数器变为大于零。

  • 释放(Release)操作: 当线程完成对资源的使用后,它必须释放信号量。释放操作会使计数器加一,表示资源又变得可用。如果有其他线程正在等待这个信号量,其中一个线程(或多个,取决于计数器增加的值)将被唤醒并获得资源访问权限。

  • 这里以一个停车场停车为例子

from threading import Thread, Semaphore
import time
import random


def task(semaphore, i):
    semaphore.acquire()
    print(f'宝马{i}号抢到了车位')
    time.sleep(random.randint(1, 3))
    semaphore.release()
    print(f'宝马{i}离开了车位')


if __name__ == '__main__':
    semaphore = Semaphore(5)
    t_list = [Thread(target=task, args=(semaphore, i)) for i in range(1, 11)]
    for t in t_list:
        t.start()

'''
宝马1号抢到了车位
宝马2号抢到了车位
宝马3号抢到了车位
宝马4号抢到了车位
宝马5号抢到了车位
宝马3离开了车位
宝马1离开了车位
宝马6号抢到了车位
宝马4离开了车位
宝马8号抢到了车位
宝马7号抢到了车位
宝马2离开了车位
宝马9号抢到了车位
宝马5离开了车位
宝马10号抢到了车位
宝马7离开了车位
宝马10离开了车位
宝马9离开了车位
宝马6离开了车位
宝马8离开了车位
进程已结束,退出代码0

'''

  • 前五个线程都会直接抢到这把锁,因为信号量为5,
  • 之后就会释放一个锁进一个

【4】event事件

  • event事件可以让一个子进程或者子线程等待另一个子进程或者子线程执行完毕再执行

  • 相当于join()方法可以让主进程等待调用join()方法的子线程执行完毕再执行。

  • Event 对象在 Python 的 threading 模块中提供,它有以下几个关键的特性和方法:

  1. 状态标志: Event 对象内部维护一个内部标志,它可以被设置为 TrueFalse。默认情况下,这个标志为 False
  2. set() 方法: 当调用 set() 方法时,Event 对象的内部标志被设置为 True。这通常表示某个特定事件已经发生,或者某个条件已经满足。
  3. clear() 方法: 当调用 clear() 方法时,Event 对象的内部标志被重置为 False
  4. wait() 方法: 线程调用 wait() 方法时会被阻塞,直到 Event 对象的内部标志被设置为 True。如果在调用 wait() 时内部标志已经是 True,那么线程将继续执行而不会阻塞。
  5. is_set() 方法: 返回 Event 对象内部标志的当前状态(TrueFalse)。
  • 这里以一个公交车上车的例子讲述
from threading import Thread, Event, Semaphore
import time


def bus(event):
    print('公交车即将到站')
    time.sleep(3)
    print('公交车到站了')
    event.set()


def waiter(i, event):
    print(f'乘客{i}正在等车')
    event.wait()
    print(f'乘客{i}上车出发')


if __name__ == '__main__':
    semaphore = Semaphore(5)
    event = Event()
    t_bus = Thread(target=bus, args=(event,))
    t_waiter_list = [Thread(target=waiter, args=(i, event)) for i in range(1, 11)]
    t_bus.start()
    for t_waiter in t_waiter_list:
        t_waiter.start()

'''
公交车即将到站
乘客1正在等车
乘客2正在等车
乘客3正在等车
乘客4正在等车
乘客5正在等车
乘客6正在等车
乘客7正在等车
乘客8正在等车
乘客9正在等车
乘客10正在等车
公交车到站了
乘客1上车出发
乘客2上车出发
乘客6上车出发
乘客8上车出发
乘客4上车出发
乘客9上车出发
乘客5上车出发
乘客10上车出发
乘客3上车出发
乘客7上车出发

进程已结束,退出代码0

'''
  • 我起了一个bus的线程,还有多个waiter的线程
  • 在bus的公交车到站后面加上一个set()
  • 在乘客上车前加上一个wait()
  • 程序运行到wait()会被阻塞
  • 直到公交车到站,也就是set()将其内部的标志打为True,wait()才不会被阻塞

标签:__,task,Thread,车位,抢到,事件,线程,event
From: https://www.cnblogs.com/Hqqqq/p/17976973

相关文章

  • JavaScript常用事件详解
    一、用于form(表单)的事件在网页中经常会遇到一些表单的验证,是通过事件进行处理的,比如用户输入用户名之后,及时显示用户是否被注册用于form(表单)的事件事件名功能onblur|当元素失去焦点时运行onchange|当元素值被改变时运行onfocus|当元素获取焦点时运行onselect......
  • 我恨 gevent
    报错了一晚上,最后发现是python版本不对。3.11,3.12,3.8,3.10试了个遍,最后3.10终于编译通过了......
  • 2024-1-19阻止事件
    目录阻止事件没有添加阻止事件:添加阻止事件区别点:阻止事件为什么要有阻止事件这里有个情况,但我的输入框内没有输入字符串就被提交的时候,我需要它显示提示文字,但是如果没有阻止事件的参与就有可能无法长久显示没有添加阻止事件:例子如下<!DOCTYPEhtml><html> <head> <met......
  • Dynamics 365 事件执行管道
    MicrosoftDynamics365事件处理子系统根据消息管道执行模型执行插件。MicrosoftDynamics365Web应用程序中的用户操作或者插件或其他应用程序执行的SDK方法调用会导致将消息发送到组织Web服务。该消息包含业务实体信息和核心操作信息。该消息是通过事件执行管道传递......
  • 快速评估您的IT事件管理实践
    您在寻找提高事件响应效率和有效性的方法吗?为什么需要评估IT事件管理?尽管改进组织的事件管理实践不会一蹴而就,但我们还是要从制定明确的事件响应计划开始。使用ServiceDeskPlus,快速检查您的事件管理实践是否符合行业标准,并进一步优化您的响应能力。当涉及到IT事件时,即使是最......
  • 第30节: Vue3 监听事件
    在UniApp中使用Vue3框架时,你可以使用监听事件来响应用户的操作。下面是一个示例,演示了如何在UniApp中使用Vue3框架使用监听事件:<template><view><button@click="handleClick">Clickme</button></view></template><scriptsetup>import{......
  • 深入理解JavaScript堆栈、事件循环、执行上下文、作用域以及闭包
    合集-JavaScript进阶系列(5) 1.JavaScriptthis绑定详解01-092.JavaScriptapply、call、bind函数详解01-093.JavaScriptforEach方法跳出循环01-024.深入理解JavaScript堆栈、事件循环、执行上下文和作用域以及闭包01-105.JavaScript到底应不应该加分号?JavaScript自......
  • 2024-1-19事件绑定,input与hover事件
    目录事件绑定,input与hover事件事件绑定hover事件input事件事件绑定.on()方法注意:off()方法事件绑定,input与hover事件在jQ内很多中事件常用的事件有下面的click(function(){...})//绑定一个点击事件hover(function(){...})//悬停触发事件blur(function(){...})//失焦事件处理......
  • Nginx基础配置详解(main、events、http、server、location)
    Nginx基础配置详解(main、events、http、server、location):https://blog.csdn.net/weixin_43834401/article/details/130562289?ops_request_misc=&request_id=&biz_id=102&utm_term=nginx%20server%20%E7%9A%84%E6%A0%B9%E7%9B%AE%E5%BD%95&utm_medium=distribute.pc_......
  • 2024-1-19事件绑定,input与hover事件
    目录事件绑定,input与hover事件事件绑定hover事件input事件事件绑定,input与hover事件在jQ内很多中事件常用的事件有下面的click(function(){...})//绑定一个点击事件hover(function(){...})//悬停触发事件blur(function(){...})//失焦事件处理focus(function(){...})//焦点......