Semaphore
Semaphore
Semaphore(信号量)是一种有限资源的进程同步管理机制。例如银行的业务办理,所有客户都会拿到一个号码,而后号码会被业务窗口叫号,被叫号的办理者就可以办理业务。
Semaphore类本质上是一种带有计数功能的进程同步机制,acquire()减少计数,release()增加计数。当可用信号量的计数为0时,后续获取信号量的进程将被阻塞。
Lock一般是针对于一个资源互斥访问的,而Semaphore是针对有限资源的并发访问。
信号量同步处理
import multiprocessing
import time
def work(semaphore):
with semaphore:
print("[Process %d] Start" % multiprocessing.current_process().pid)
time.sleep(2)
print("[Process %d] End" % multiprocessing.current_process().pid)
def main():
semaphore = multiprocessing.Semaphore(3)
workers = [multiprocessing.Process(target=work, args=(semaphore,))
for _ in range(10)]
for worker in workers:
worker.start()
for worker in workers:
worker.join()
if __name__ == "__main__":
main()一个信号量Semaphore是一个整型量,除对其初始化外,它只能由两个原子操作wait()和signal()进行访问。wait()和signal()即早前使用的P/V操作,P/V的名称来源于荷兰文proberen(测试)和verhogen(增量)。
wait(s) {
while (s <= 0) { }
s--;
}
signal(s) {
s++;
}但这并不是信号量的最终实现,最终的信号量实现最好是能解决两个问题:
- 不忙等。
- 记录等待的进程数量。
为了避免进程忙等,wait()和signal()的定义需要进行修改。当一个进程执行wait()但发现没有可用许可时,它必须等待,这里的等待不是忙等,而是阻塞自己。当一个进程阻塞且等待信号量时,在其它进程执行signal()之后被唤醒并进入就绪状态。
带符号计数实现中,信号量的意义为:
- :有s个资源可用。
- :无资源可用。
- :等待队列中有个进程。
为了定义基于阻塞(block)和唤醒(wakeup)的信号量,可以将信号量定义为如下结构:
typedef struct {
int value;
struct process *list;
} Semaphore;无需忙等的wait() / signal(),其计数与队列更新必须作为协调的原子协议:
wait(Semaphore *s) {
s->value--;
if (s->value < 0) {
add this process to s->list;
block();
}
}
signal(Semaphore *s) {
s->value++;
if (s->value <= 0) {
remove a process from s->list;
wakeup(that process);
}
}互动实验
Semaphore:银行营业厅
访问权限PRO
PRO EXCLUSIVE探索不止于此
尊享 Pro 权益解锁完整互动实验、进阶解析与精选参考答案。
动手练习
认识信号量计数
追踪初值为3的信号量。
- 多少个工作者能直接获取许可而不等待?
- 按带符号计数模型,四次获取尝试后值是多少?
- 此时释放一次许可会发生什么?