文章目录
- 一、前言
- 二、生产者-消费者模型
- 2.1、代码
- 2.2、运行的结果
- 2.3、Semaphore没有设置上限值
一、前言
先说一下信号量与互斥量之间的关系。信号量的一个特殊的应用是互斥锁(互斥量),当信号量的最大数量是1时,它跟互斥锁(互斥量)的作用相同。
以下摘自《python并行编程》中文版:
二、生产者-消费者模型
本次的代码目的如下:
- 生成者producer每隔3秒时间同步一次消费者1(customer1)与消费者2(customer2)。
- 消费者1(customer1)与消费者2(customer2)每一次被同步都可以运行两次。
2.1、代码
# python3.9
import time
import threading
se1 = threading.Semaphore(0) # se1信号量的初始数量是0
se2 = threading.Semaphore(0) # se2信号量的初始数量是0
# 消费者1线程函数
def customer1():
global se1
while True:
# print("customer1请求se1信号量。")
se1.acquire() # 向se1信号量请求一个信号
print("customer1请求信号量成功,time:%s" % time.perf_counter())
# 消费者2线程函数
def customer2():
global se2
while True:
# print("customer2请求se2信号量。")
se2.acquire() # 向se1信号量请求一个信号
print("customer2请求信号量成功,time:%s" % time.perf_counter())
# 生产者线程函数
def producer():
while True:
time.sleep(3) # 休眠3秒钟
# 释放se1两个信号
se1.release()
se1.release()
# 释放se2两个信号
se2.release()
se2.release()
print("producer释放完信号量,其他线程将被同步。time:%s" % time.perf_counter())
# 主线程函数
def main():
t1 = threading.Thread(target=producer,name="thread_producer",daemon=True) # 创建producer子线程
t2 = threading.Thread(target=customer1,name="thread_customer1",daemon=True) # 创建cusotmer1子线程
t3 = threading.Thread(target=customer2,name="thread_customer2",daemon=True) # 创建customer2子线程
t1.start() # 启动producer线程
t2.start() # 启动customer1线程
t3.start() # 启动customer2线程
t1.join() # 子线程producer是无限循环的线程,所以主线程需要等待它运行结束
t2.join() # 子线程customer1是无限循环的线程,所以主线程需要等待它运行结束
t3.join() # 子线程customer2是无限循环的线程,所以主线程需要等待它运行结束
print("主线程运行结束!")
if __name__ == "__main__":
main()
2.2、运行的结果
python多线程的信号量跟单片机RTOS的信号量真的很相似。如果之前接触过RTOS的信号量的话,python的信号量也很快可以掌握。
2.3、Semaphore没有设置上限值
在代码中,只设置了信号量的初始值。
因为我将信号量的初始值设为0,所以线程customer1与线程customer2在刚被创建的时候就进入了阻塞态(因为没有信号量)。
Semaphore没有设置上限值,所以可能会出现信号量释放的次数过多(多于本来规划的值)。为了避免这个情况的出现,Python的多线程还有另外一个工具叫做有界信号量。
单片机的RTOS上的信号量跟python的有界信号量一样,能防止信号量释放的次数过多。