IPC机制之信号量及pv操作

关于IPC我们要知道的一些内容

什么是IPC?

答:IPC 全称 Inter-Process Communication,我们可以按照其字面意思来理解,就是指进程间沟通的一种方法。其实我们以前就接触过一些IPC机制,只是当时我们还没有认识到,那就是:管道和信号,这两者都可以达到进程间通信的目的。其实IPC机制还有信号量,共享内存,消息队列,套接字。我们之后会一一介绍,本篇先介绍信号量。

什么是临界资源和临界区?

答:当一个进程对一块内存所保存的资源进行读或写时,也许会有其他的进程同时会对这些资源进行访问或者修改,这就引发一个问题,比如,这里存放了一个变量 a 的值是123,进程一刚要获取这个a的值,结果进程二却抢在进程一之前把a的值修改成了456,导致进程a获取到了不正确的值。所以,我们有了临界资源这一定义,临界资源是一次仅允许一个进程使用的共享资源。即我在访问这些资源的时候,不能有其它进程来对其进行访问或修改。而临界区是指每个进程中访问临界资源的那段代码

什么是原子操作?

答:简单来讲就是原子操作是不可分割的,在执行完毕之前不会被任何其它任务或事件中断。举个例子:我们平时做菜有个行为的顺序是洗菜、切菜、炒菜,这三道工序我们顺序执行,而当我们切菜时,假如有人敲门,你会停止切菜去开门,这是很正常的操作。而假如这个行为是个原子操作,你必须把洗菜、切菜、炒菜,这三道工序彻底完成才能做其他的事情,这个行为只有成功和失败两个结果,不可能存在第三种情况,比如我切菜切到一半停下来,静止几分钟再继续,这是不允许的。我们常用的 i++ 就不是一个原子操作,这个语句经历了三个阶段:内存到寄存器、寄存器自增、写回内存。这三个阶段都有可能被中断分离,从而导致 i 不正确的自增结果。

什么是信号量?

答:信号量按照我自己的理解就是一个变量,它规定了在当前的值下你能做和不能做的事情。最简单的一个例子就是红绿灯,我们可以把这个灯看作是一个信号量,当其为红色,表示车辆禁止前进,绿灯,表示车辆可以前进。

什么是pv操作?

答:pv操作是针对信号量的一种原子操作,通过信号量和pv操作达到对临界资源的管理。在一般的编程中,我们会把信号量的值初始化为 1,而pv操作就是对这个信号量的值进行加减。

假设当前当信号量 s = 1 。

当 s = 1时, 表示该临界资源可以访问或修改。

当 s = 0 时,表示该临界区不可被访问或修改。

p 操作,会把信号量的值减一。

v 操作,会把信号量的值加一。

我们试想,信号量此时的值为 1 ,当进程一要访问某临界资源,首先判断信号量的值,发现其为 1,说明可以访问,于是进程一进行p操作,对信号量的值减一,这样,当其他进程想要访问该临界资源,发现信号量的值为0,不能访问,只好等待。当进程一对这块临界资源访问结束,进行v操作,把信号量的值恢复成 1,其它进程就可以访问了。

使用PV操作实现进程互斥时应该注意的是:
(1)每个程序中用户实现互斥的P、V操作必须成对出现,先做P操作,进临界区,后做V操作,出临界区。若有多个分支,要认真检查其成对性。
(2)P、V操作应分别紧靠临界区的头尾部,临界区的代码应尽可能短,不能有死循环。
  (3)互斥信号量的初值一般为1。

-------------------------

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
pv操作中,sleep(1)的作用是让执行pv操作的进程阻塞1秒钟,等待资源可用。这个功能可以通过信号量机制来实现。 在信号量机制中,当信号量的值小于0时,调用semop操作的进程会被阻塞。我们可以在pv操作中使用一个计时器来实现阻塞1秒钟的功能。具体实现步骤如下: 1. 定义一个信号量,初始值为1,用来表示资源的可用性。 2. 在执行pv操作的进程中,调用semop操作,将信号量的值减1。 3. 如果信号量的值小于0,则调用sleep(1)函数,等待1秒钟。 4. 1秒钟后,再次调用semop操作,将信号量的值减1,并继续执行pv操作。 下面是一个简单的C语言代码示例,演示了如何使用信号量机制模拟实现pv操作中sleep(1)的作用。 ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/sem.h> int main() { int sem_id = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666); if (sem_id == -1) { perror("semget error"); exit(EXIT_FAILURE); } // 初始化信号量的值为1,表示资源可用 semctl(sem_id, 0, SETVAL, 1); // 执行pv操作,将信号量的值减1 struct sembuf sem_op = {0, -1, SEM_UNDO}; if (semop(sem_id, &sem_op, 1) == -1) { perror("semop error"); exit(EXIT_FAILURE); } // 检查信号量的值是否小于0 int sem_val = semctl(sem_id, 0, GETVAL, 0); if (sem_val < 0) { // 如果信号量的值小于0,则等待1秒钟 sleep(1); } // 再次执行pv操作,将信号量的值减1 if (semop(sem_id, &sem_op, 1) == -1) { perror("semop error"); exit(EXIT_FAILURE); } // 释放信号量 if (semctl(sem_id, 0, IPC_RMID, 0) == -1) { perror("semctl error"); exit(EXIT_FAILURE); } return 0; } ``` 在这个例子中,我们使用semget函数创建了一个信号量,然后使用semctl函数将其初始化为1。接着,我们执行了一次pv操作,将信号量的值减1。如果信号量的值小于0,则调用sleep(1)函数等待1秒钟。最后,我们再次执行pv操作,将信号量的值减1。注意,我们在结尾处使用了semctl函数来释放信号量

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值