Python中的PV操作

原文链接:https://blog.csdn.net/qq_40760732/article/details/89513663
仅为学习记录
PV操作的特点:

原子性,P和V操作不可分!
连续性,P和V操作是不间断的。
P自己,V对方:P的是自己的信号量减1,V的是对方的信号量加1.

文章开头,先来一段要背的内容

接下来,先给两个网上的案例热热身
案例一:

import threading,time
lock_1 = threading.Semaphore(1)     #检查售票员是否关门
lock_2 = threading.Semaphore(0)     #检查司机是否停车
def 司机():
    for i in range(3):
 
            lock_1.acquire()
            print('司机开车')
            time.sleep(1)
            print('驾驶')
            print('到站停车')
 
            lock_2.release()
def 售票员():
    for i in range(3):
 
            lock_2.acquire()
            time.sleep(1)
            print('打开车门')
            print('乘客上下车')
            time.sleep(1)
            print('关上车门')
 
            lock_1.release()
if __name__=='__main__':
    p1 = threading.Thread(target=司机)
    p2 = threading.Thread(target=售票员)
    p1.start()
    p2.start()
    p1.join()
    p2.join()

解释:
1.里面的lock_1,lock_2为两个信号量;

2.lock_1.acquire()为P操作,lock_1.release()为V操作;

3.lock_1 = threading.Semaphore(1)的意思是将信号量lock_1的初值赋为1。

注意:
Semaphore管理一个内置的计数器,
每当调用acquire()时内置计数器-1;
调用release() 时内置计数器+1;
计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。

我们将lock_1的初值赋为1,lock_2的初值赋为0,则先执行司机这一线程。

案例二:

import queue,random,threading
from time import sleep
 
s_1 = threading.Semaphore(1)  # 临界区互斥信号量
s_2 = threading.Semaphore(5)  # 判断是否有空闲缓冲区的信号量
s_3 = threading.Semaphore(0)  # 判断缓冲区里是否有产品的信号量
 
 
def productor(i, q):
    while True:
        num = random.choice(['华为P30', '小米9', 'ViVo x27', 'iphone XR'])
        print('生产者%d生产了产品%s' % (i, num))
        s_2.acquire()  # 是否有空缓冲区
        s_1.acquire()  # 缓冲区是否被占用
        q.put(num)
        sleep(1)
        print('生产者%d把产品%s放入了仓库中' % (i, num))
        s_1.release()
        s_3.release()
 
 
 
def consumer(i, q):
    while True:
        s_3.acquire()
        s_1.acquire()
        num = q.get()
        sleep(1)
        print('消费者%d购买了产品%s' % (i, num))
        s_1.release()
        s_2.release()
 
 
 
if __name__ == '__main__':
    q = queue.Queue(5)  # 创建上限为5的缓冲区
 
    # 创建4个生产者
    for i in range(4):
        threading.Thread(target=productor, args=(i, q)).start()
 
    # 创建6个消费者
    for i in range(6):
        threading.Thread(target=consumer, args=(i, q)).start()

信号量:
设置三个信号量,一个信号量判断缓冲区是否被占用,一个信号量判断缓冲区是否有空,最后一个信号量判断缓冲区里是否有东西。

生产者:四个

消费者:六个

缓冲区:五个

某一时刻只能有一个线程或进程访问缓冲区,缓冲区没满时生产者可以往里面放东西,缓冲区没空时消费者可以从里面取东西。

PV操作的简单了解:
进程通常分为就绪、运行和阻塞三个工作状态。三种状态在某些条件下可以转换,三者之间的转换关系如下:

在这里插入图片描述

进程三个状态之间的转换就是靠PV操作来控制的。PV操作主要就是P操作、V操作和信号量。其中信号量起到了至关重要的作用。

信号量

信号量是最早出现的用来解决进程同步与互斥问题的机制。

信号量(Saphore)由一个值和一个指针组成,指针指向等待该信号量的进程。信号量的值表示相应资源的使用情况。信号量S>=0时,S表示可用资源的数量。执行一次P操作意味着请求分配一个资源,因此S的值减1;当S<0时,表示已经没有可用资源,S的绝对值表示当前等待该资源的进程数。请求者必须等待其他进程释放该类资源,才能继续运行。而执行一个V操作意味着释放一个资源,因此S的值加1;若S<0,表示有某些进程正在等待该资源,因此要唤醒一个等待状态的进程,使之运行下去。

注意,信号量的值只能由PV操作来改变。

最后来一句顺口溜笔记:

P减V加信号量
互斥信号量是1
唤醒进程跳临界
负阻正有0用完

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值