多线程编程之事件锁

362 阅读2分钟

1 基本介绍

事件锁是基于条件锁来做的,它与条件锁的区别在于一次只能放行全部,不能放行任意个数的子线程运行。我们可以将事件锁看成红绿灯。当红灯亮时所有线程都处于等待状态;当绿灯亮时所有线程都处于运行状态

2 相关方法

条件锁相关的方法如下:

方法描述
threading.Event()返回一个事件锁对象
threading.Event().clear()使得所有事件都处于暂停状态
threading.Event().set()使得所有事件都处于运行状态
threading.Event().is_set()判断当前事件状态,运行状态为True,暂停状态为False
threading.Event().wait(timeout=None)将当前线程设置为“暂停状态,只有该线程接到“绿灯通知”或者超时时间到期之后才会继续运行,在“等待”状态下的线程将允许系统根据策略自行切换到其他线程中运行

3 使用示例

下面有2个实例 example 01:

import threading
import time
​
event = threading.Event()
​
​
class Stack:
    def __init__(self):
        """
        栈
        """
        # 栈指针初值为0
        self.pointer = 0
        self.data = [-1, -1, -1, -1, -1]
​
    def push(self, save_data):
        """
        压栈方法
        :param save_data:要进行压栈的数据
        """
        global event
        # 栈已满,不能压栈
        while self.pointer == len(self.data):
            # 栈已满,生产线程无法添加数据
            event.wait()
        # 栈已满,通知消费线程取出数据
        event.set()
        # 数据压栈
        self.data[self.pointer] = save_data
        # 指针向上移动
        self.pointer += 1
​
    def pop(self):
        """
        出栈方法
        :return: 栈中的数据
        """
        global event
        # 栈已空,不能出栈
        while self.pointer == 0:
            # 当栈为空时,消费线程无法消费数据
            event.wait()
        # 通知生产线程产生数据
        event.set()
        # 指针向下移动
        self.pointer -= 1
        # 数据出栈
        save_data = self.data[self.pointer]
        return save_data
​
​
stack = Stack()
​
​
def producer_thread_body():
    """
    生产者线程体函数
    """
    global stack
    for num in range(10):
        stack.push(num)
        print(f'生产数据:{num}')
        time.sleep(1)
​
​
def consumer_thread_body():
    """
    消费者线程体函数
    """
    global stack
    for _ in range(10):
        x = stack.pop()
        print(f'消费:{x}')
        time.sleep(1)
​
​
def main():
    t1 = threading.Thread(target=producer_thread_body)
    t1.start()
    t2 = threading.Thread(target=consumer_thread_body)
    t2.start()
​
​
if __name__ == '__main__':
    main()

result:

生产数据:0
消费:0
生产数据:1
消费:1
生产数据:2
消费:2
生产数据:3
消费:3
生产数据:4消费:4生产数据:5消费:5生产数据:6
消费:6
生产数据:7
消费:7
生产数据:8
消费:8
生产数据:9
消费:9

example 02:

import threading
import time
​
event = threading.Event()
​
​
def task1():
    i = 0
    while True:
        if i < 3:
            event.clear()
            print('阻塞中')
        elif i == 4:
            event.set()
            print('阻塞结束')
        time.sleep(1)
        if event.is_set():
            break
        i += 1
​
​
def task2():
    while True:
        print('This is T2')
        if event.is_set():
            break
        time.sleep(2)
​
​
if __name__ == '__main__':
    t1 = threading.Thread(target=task1)
    t2 = threading.Thread(target=task2)
    t1.start()
    t2.start()
    event.wait()

result:

阻塞中
This is T2
阻塞中
This is T2
阻塞中
This is T2
阻塞结束
This is T2

4 with语句

Event()不能使用with语句,只能正常常规操作。 example 02:

import threading
import time
​
event = threading.Event()
​
​
def boss():
    print('今天加班5秒钟')
    event.clear()
    time.sleep(1)
    print('时间到了,大家回家吧')
    event.set()
​
​
def employee():
    while True:
        if event.is_set():
            print('employee:回家了')
            break
        else:
            print('employee:工作中,请勿打扰')
            event.wait()
​
​
b = threading.Thread(target=boss, )
a = threading.Thread(target=employee, )
b.start()
a.start()

result:

今天加班5秒钟
employee:工作中,请勿打扰
时间到了,大家回家吧
employee:回家了

\