> # ♻️ 资源
> **大小:** 884KB
> **文档链接:**[**https://www.yuque.com/sxbn/ks/100010138**](https://www.yuque.com/sxbn/ks/100010138)
> **➡️ 资源下载:**[**https://download.csdn.net/download/s1t16/87293616**](https://download.csdn.net/download/s1t16/87293616)
> **注:更多内容可关注微信公众号【神仙别闹】,如当前文章或代码侵犯了您的权益,请私信作者删除!**
> ![qrcode_for_gh_d52056803b9a_344.jpg](https://cdn.nlark.com/yuque/0/2023/jpeg/2469055/1692147256036-49ec7e0c-5434-4963-b805-47e7295c9cbc.jpeg#averageHue=%23a3a3a3&clientId=u8fb96484-770e-4&from=paste&height=140&id=u237e511a&originHeight=344&originWidth=344&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=8270&status=done&style=none&taskId=ud96bf5f7-fe85-4848-b9c2-82251181297&title=&width=140.1999969482422)
# 信号量的实现与应用
## 实验内容
1. 在 Ubuntu 下编写程序,用信号量解决生产者-消费者问题
在 Ubuntu 下编写应用程序 `pc.c`,解决经典的生产者-消费者问题,完成下面的功能:
- 建立一个生产者进程,N 个消费者进程(N > 1)
- 用文件建立一个共享缓冲区
- 生产者进程依次向缓冲区写入整数 0,1,2,...,M, M >= 500
- 消费者进程从缓冲区读数,每次读一个,并将读出的数字从缓冲区删除,然后将本进程 ID+ 数字输出到标准输出
- 缓冲区同时最多只能保存 10 个数
`pc.c` 中将会用到 `sem_open()`,`sem_unlink()`,`sem_wait()`,`sem_post()` 等信号量相关的系统调用,请查阅相关文档。
2. 在 0.11 中实现信号量,用生产者-消费者程序检验之
Linux 在 0.11 版还没有实现信号量,Linus 把这件富有挑战的工作留给了你。如果能够实现一套山寨版的完全符合 POSIX 规范的信号量,无疑是很有成就感的。但时间暂时不允许我们这么做,所以先弄一套缩水版的类 POSIX 信号量,它的原型和标准并不完全相同,而且只包含如下系统调用:
```c
sem_t *sem_open(const char *name, unsigned int value);
int sem_wait(sem_t *sem);
int sem_post(sem_t *sem);
int sem_unlink(const char *name);
```
- `sem_t` 是信号量类型,根据实现的需要自定义
- `sem_open`
功能是创建一个信号量,或打开一个已经存在的信号量。
`name` 是信号量的名字。不同的进程可以通过提供同样的 `name` 而共享同一个信号量。如果该信号量不存在,就创建新的名为 `name` 的信号量;如果存在,就打开已经存在的名为 `name` 的信号量。
`value` 是信号量的初值,仅当新建信号量时,此参数才有效,其余情况下它被忽略。
当成功时,返回值是该信号量的唯一标识(比如,在内核的地址,ID 等),由另外两个系统调用使用。如失败,返回值是 NULL。
- `sem_wait`
信号量的 P 原子操作。如果继续运行的条件不满足,则令调用进程等待在信号量 `sem` 上。
返回 0 表示成功,返回-1 表示失败。
- `sem_post`
信号量的 V 原子操作。如果有等待 `sem` 的进程,它会唤醒其中的一个。返回 0 表示成功,返回-1 表示失败。
- `sem_unlink`
功能是删除名为 `name` 的信号量。返回 0 表示成功,返回-1 表示失败。
在 _kernel_ 目录下新建 `sem.c` 文件实现如下功能。然后将 `pc.c` 从 Ubuntu 移植到 0.11 下,测试自己实现的信号量。
3. 实验报告
1. 在 `pc.c` 中去掉所有与信号量有关的代码,再运行程序,执行效果有变化吗?为什么会这样?
2. 实验的设计者在第一次编写生产者-消费者程序的时候,是这么做的:
```c
Producer()
{
P(Mutex); //互斥信号量
生产一个产品item;
P(Empty); //空闲缓存资源
将item放到空闲缓存中;
V(Full); //产品资源
V(Mutex);
}
Consumer()
{
P(Mutex);
P(Full);
从缓存区取出一个赋值给item;
V(Empty);
消费产品item;
V(Mutex);
}
```
这样可行吗?如果可行,那么它和标准解法在执行效果上会有什么不同?如果不可行,那么它有什么问题使它不可行?
## 实验过程
### 实验结果
1. 在 Ubuntu 上运行 pc.c 的结果:
![d9123628a1f13d61c499987ace71a4df.png](https://cdn.nlark.com/yuque/0/2024/png/2469055/1704274029740-0376a804-8bfc-4ed3-9113-e1a573e76f39.png#averageHue=%23f4f2d1&clientId=u3ced2e2c-8719-4&from=paste&height=486&id=uc6f8e8ec&originHeight=608&originWidth=903&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=183030&status=done&style=none&taskId=u5bc49149-7043-4c8d-b71e-bdb2ad40a2b&title=&width=722.4)
2. 在添加了实现信号量的 0.11 上运行移植好的 pc.c 的结果:
![11ff18e51265e6f9062a59b1b7fa34d9.png](https://cdn.nlark.com/yuque/0/2024/png/2469055/1704274063364-e9a902d1-6dc9-4d5f-999b-1d7aaa9d2a4a.png#averageHue=%23f5f4d4&clientId=u3ced2e2c-8719-4&from=paste&height=514&id=u5c3323d5&originHeight=642&originWidth=876&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=111377&status=done&style=none&taskId=u4c04ba00-dac2-44b7-aba8-c35e3f987d8&title=&width=700.8)![27e417f62c587ff1eae720e247589e83.png](https://cdn.nlark.com/yuque/0/2024/png/2469055/1704274063328-7160f75c-66ac-417d-9f75-f21dfc5f3f1c.png#averageHue=%23202020&clientId=u3ced2e2c-8719-4&from=paste&height=382&id=u32597365&originHeight=478&originWidth=720&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=22595&status=done&style=none&taskId=u409c14f9-e86d-4db4-aebd-ac3681cc23d&title=&width=576)
### 实验分析
#### 1. 从生产者-消费者问题看进程同步
##### 1.1 信号量实现进程同步
生产者负责往缓冲区写入数据,消费者从缓冲区取走生产者写入的数据,缓冲区就是这个过程的共享资源。如果生产者还不曾向缓冲区写入数据,消费者就从缓冲区读取;或者生产者数据写入还未完成,消费者就读取。这两种情况消费者读取到的都是非法数据。如果缓冲区已满,生产者继续往其中写入数据,就会覆盖尚未被消费者读取的数据,造成数据丢失。就像多人参与的项目需要分工协调,多个进程对共享资源的使用也必须进行同步。进程同步就是让进程在必要的地方停下来,等待其他进程执行到满足一定的条件后,再继续执行,从而保证多个进程合理有序的推进。
就生产者-消费者问题,进程同步就是要保证:
对于生产者来说,当缓冲区满,也就是空闲缓冲区个数为 0 时,此时生产者不能继续向缓冲区写数,必须等待,直到有消费者从满缓冲区取走数后,再次有了空闲缓冲区,生产者才能向缓冲区写数。并且当缓冲区满时,先后有多个生产者均想往缓冲区写入,那么它们均需要等待,此时需要记录下等待的生产者的个数,以便缓冲区有空闲空间后,所有等待的生产者都会得到唤醒,确保请求写入的生产者最终都能写入到缓冲区。
对于消费者来说,当缓冲区空时,此时没有数可以被取走,消费者必须等待,直到有生产者向缓冲区写数后,消费者才能取数。并且如果当缓冲区空时,先后有多个消费者均想从缓冲区取数,那么它们均需要等待,此时需要记录下等待的消费者的个数,以便缓冲区有数可取后,所有等待的消费者都会得到唤醒,确保请求取数的消费者最终都能取到数。
也就是说,当多个进程需要协同合作时,需要根据某个信息,判断当前进程是否需要停下来等待;同时,其他进程需要根据这个信息判断是否有进程在等待,或者有几个进程在等待,以决定是否需要唤醒等待的进程。而这个信息,就是信号量。
信号量是一个计数器,用于为多个进程提供对共享数据对象的访�
基于 C语言 的信号量实现与应用【100010138】
版权申诉
5星 · 超过95%的资源 125 浏览量
2022-12-15
15:25:58
上传
评论
收藏 885KB ZIP 举报
神仙别闹
- 粉丝: 2680
- 资源: 7667
最新资源
- 基于Matlab的异常姿势识别系统+源代码+全部数据+文档说明+详细注释+使用说明+截图(高分课程设计)
- 隐藏文件展示工具,用来展示被病毒隐藏的文件
- 基于Matlab的图像分割系统+源代码+全部数据+文档说明+详细注释+使用说明+截图(高分课程设计)
- 基于MATLAB指纹门禁GUI设计源码+源代码+全部数据+文档说明+详细注释+使用说明+截图(高分课程设计)
- 基于Matlab的仪表指数识别系统霍夫曼变换+源代码+全部数据+文档说明+详细注释+使用说明+截图(高分课程设计)
- 基于MATLAB 的霍夫曼变换答题卡识别带GUI界面+源代码+全部数据+文档说明+详细注释+使用说明+截图(高分课程设计)
- 基于MATLAB 疲劳驾驶检测专识别GUI源码+全部数据+文档说明+详细注释+使用说明+截图(高分课程设计)
- 基于matlab的虫害侵蚀系统带Gui界面+源代码+全部数据+文档说明+详细注释+使用说明+截图(高分课程设计)
- 基于Matlab的教室人数统计系统 可以统计正脸情况下的人数+源代码+全部数据+文档说明+详细注释+使用说明+截图(高分课程设计
- 基于MATLAB的水果分级系统,带GUI界面+源代码+全部数据+文档说明+详细注释+使用说明+截图(高分课程设计)
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈