多线程--信号对象(Semaphore)

Semaphore工作原理:

Semaphore对象支持上下文管理协议。
Semaphore对象内部管理一个计数器,并有两个方法对计数器工作:
1.acquire(blocking=True, timeout=None)
2.release()
该计数器由每个acquire()调用递减,并由每个release()调用递增。计数器永远不会低于零,当acquire()发现计数器为零时,线程阻塞,等待其他线程调用release()

 当blocking=True时:如果调用时计数器大于零,则将其减1并立即返回。如果在调用时计数器为零,则阻塞并等待,直到其他线程调用release()使其大于零。因此如果多个acquire() 被阻塞,release()将只唤醒其中一个,这个过程会随机选择一个,因此不应该依赖阻塞线程的被唤醒顺序。

计算方式:release()调用数减去acquire()调用数加一个初始值的计数器

 

demo: 两个不同的线程将会共用一个 FooBar 实例。其中一个线程将会调用 foo() 方法,另一个线程将会调用 bar() 方法。

输入: n = 1
输出: "foobar"
解释: 这里有两个线程被异步启动。其中一个调用 foo() 方法, 另一个调用 bar() 方法,"foobar" 将被输出一次。

思路:信号交替,调用acquire()则+1 ,调用release()则 -1

 1 import threading
 2 
 3 
 4 class FooBar:
 5     def __init__(self, n):
 6         self.n = n
 7         self.demotex1 = threading.Semaphore(1) 
 8         self.demotex2 = threading.Semaphore(0)
 9         
10 
11     def foo(self, printFoo: 'Callable[[], None]') -> None:
12         
13         for i in range(self.n):
14             self.demotex1.acquire()  # -1 
15             # printFoo() outputs "foo". Do not change or remove this line.
16             printFoo()
17             self.demotex2.release()  # +1  释放信号,使计数器递增1。当计数器为零并有另一个线程等待计数器大于零时,唤醒该线程。
18             
19 
20 
21     def bar(self, printBar: 'Callable[[], None]') -> None:
22         
23         for i in range(self.n):
24             self.demotex2.acquire() 
25             # printBar() outputs "bar". Do not change or remove this line.
26             printBar()
27             self.demotex1.release()

该题来自力扣

 

posted @ 2020-08-10 16:12  Lei、Sunny  阅读(194)  评论(0编辑  收藏  举报