接上一篇文章
一、引言
此问题是操作系统中的一个经典的同步异步问题,是我们操作系统课程中非常重要的一部分。实验要求我们用C语言在Linux操作系统下利用信号量函数和共享内存函数实现经典的生产者消费者问题。也借此博客把所学知识记录下来。实验要求如下:
在Linux操作系统下用C实现经典同步问题:生产者—消费者,具体要求如下:
(1)一个大小为10的缓冲区,初始状态为空。
(2)2个生产者,随机等待一段时间,往缓冲区中添加数据,若缓冲区已满,等待消费者取走数据之后再添加,重复10次。
(3)2个生产者,随机等待一段时间,往缓冲区中读取数据,若缓冲区为空,等待生产者添加数据之后再读取,重复10次。
(4)当前只能有一个进程对这个缓冲区进行操作 。
(5)缓冲区采用循环队列表示,利用头、尾指针来存放、读取数据,以及判断队列是否为空。缓冲区中数组大小为10。
(6)利用随机函数rand()得到A~Z的一个随机字符,作为生产者每次生产的数据,存放到缓冲区中。
(7)使用shmget()系统调用实现共享主存段的创建,shmget()返回共享内存区的ID。对于已经申请到的共享段,进程需把它附加到自己的虚拟空间中才能对其进行读写。
(8)信号量的建立采用semget()函数,同时建立信号量的 数量。在信号量建立后,调用semctl()对信号量进行初始2化 ,例如本实验中,可以建立两个信号量SEM_EMPTY、 SEM_FULL,初始化时设置SEM_EMPTY为10,SEM_FULL 为0。使用操 作信号的函数semop()做排除式操作,使用这个 函数防止对共享内存的同时操作。对共享内存操作完毕后采用shmctl()函数撤销共享内存段。
(9)使用循环,创建2个生产者以及2个消费者,采用函数 fork()创建一个新的进程。
(10)一个进程的一次操作完成后,采用函数fflush()刷新缓冲区。
(11)程序最后使用semctl()函数释放内存。
二、生产者消费者问题
三、信号量
抽象的来讲,信号量(signal)的特性如下:信号量是一个非负整数,所有通过它的线程/进程都会将该整数减一(通过它当然是为了使用资源),当该整数值为零时,所有试图通过它的线程都将处于等待状态。在信号量上我们定义两种操作: Wait(等待) 和 Release(释放)。当一个线程调用Wait操作时,它要么得到资源然后将信号量减一,要么一直等下去(指放入阻塞队列),直到信号量大于等于一时。Release(释放)实际上是在信号量上执行加操作,对应于车辆离开停车场,该操作之所以叫做“释放”是因为释放了由信号量守护的资源。在通用术语上我们将此两种操作成为P、V操作。而操作的对象就是信号量(signal),用来实现线程/进程的同步、异步和互斥。
四、共享内存函数
共享内存函数由shmget、shmat、shmdt、shmctl四个函数组成。下面的表格列出了这四个函数的函数原型及其具体说明。
1. shmget函数原型
shmget(得到一个共享内存标识符或创建一个共享内存对象) |
||
所需头文件 |
#include <sys/ipc.h> #include <sys/shm.h> |
|
函数说明 |
得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符 |
|
函数原型 |
int shmget(key_t key, size_t size, int shmflg) |
|
函数传入值 |
key |
0(IPC_PRIVATE):会建立新共享内存对象 |
大于0的32位整数:视参数shmflg来确定操作。通常要求此值来源于ftok返回的IPC键值 |
||
size |
大于0的整数:新建的共享内存大小,以字节为单位 |
|
0:只获取共享内存时指定为0 |
||
shmflg |
0:取共享内存标识符,若不存在则函数会报错 |
|
IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符 |
||
IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相等的共享内存,则新建一个消息队列;如果存在这样的共享内存则报错 |
||
函数返回值 |
成功:返回共享内存的标识符 |
|
出错:-1,错误原因存于error中 |
||
附加说明 |
上述shmflg参数为模式标志参数,使用时需要与IPC对象存取权限(如0600表示用户可以读写改内存)进行|运算来确定信号量集的存取权限 |
|
错误代码 |
EINVAL:参数size小于SHMMIN或大于SHMMAX EEXIST:预建立key所指的共享内存,但已经存在 EIDRM:参数key所指的共享内存已经删除 ENOSPC:超过了系统允许建立的共享内存的最大值(SHMALL) ENOENT:参数key所指的共享内存不存在,而参数shmflg未设IPC_CREAT位 EACCES:没有权限 ENOMEM:核心内存不足 |
在Linux环境中,对开始申请的共享内存空间进行了初始化,初始值为0x00。
如果用shmget创建了一个新的消息队列对象时,则shmid_ds结构成员变量的值设置如下:
shm_lpid、shm_nattach、shm_atime、shm_dtime设置为0。
msg_ctime设置为当前时间。
shm_segsz设成创建共享内存的大小。
shmflg的读写权限放在shm_perm.mode中。
shm_perm结构的uid和cuid成员被设置成当前进程的有效用户ID,gid和cuid成员被设置成当前进程的有效组ID。
2. shmat函数原型
shmat(把共享内存区对象映射到调用进程的地址空间) |
||
所需头文件 |