0%

信号量的实现和应用

信号量的实现与应用

知识储备

在消费者与生产者实现时,需要进行文件读写,实验指导书中提到,可通过借助标准C库函数来实现,或者直接通过对应的系统调用。

image-20220526193310932

这里列出关于文件读写的三个函数说明

fseek()

C 库函数 int fseek(FILE *stream, long int offset, int whence) 设置流 stream 的文件位置为给定的偏移 offset,参数 offset 意味着从给定的 whence 位置查找的字节数。

声明如下

1
2
int fseek(FILE *stream, long int offset, int whence)
如fseek( fp, 5, SEEK_SET )就是把文件指针fp移动到距离文件开头5个字节处。

参数:

1
2
3
stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
offset -- 这是相对 whence 的偏移量,以字节为单位。
whence -- 这是表示开始添加偏移 offset 的位置。它一般指定为下列常量之一:
常量 描述
SEEK_SET 文件的开头
SEEK_CUR 文件指针的当前位置
SEEK_END 文件的末尾

返回值:如果成功,则该函数返回0,否则返回非零值。

fread()

C 库函数 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) 从给定流 stream 读取数据到 ptr 所指向的数组中。

声明如下

1
2
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
如fread(&productid,sizeof(int),1,fp) 就是从fp指向的文件中,读取一个int长度的元素

参数

1
2
3
4
ptr -- 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
size -- 这是要读取的每个元素的大小,以字节为单位。
nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流

返回值:成功读取的元素总数会以 size_t 对象返回,size_t 对象是一个整型数据类型。如果总数与 nmemb 参数不同,则可能发生了一个错误或者到达了文件末尾。

fwrite()

C 库函数 size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)ptr 所指向的数组中的数据写入到给定流 stream 中。

声明如下

1
2
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
如fwrite(&Outpos,sizeof(int),1,fp)是向fp指向的文件中写入1个int长度的Outpos变量中的内容

参数

1
2
3
4
ptr -- 这是指向要被写入的元素数组的指针。
size -- 这是要被写入的每个元素的大小,以字节为单位。
nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输出流。

返回值:如果成功,该函数返回一个 size_t 对象,表示元素的总数,该对象是一个整型数据类型。如果该数字与 nmemb 参数不同,则会显示一个错误。

步骤

实现信号量

新建sem头文件sem.h

在linux-0.11/include/linux目录下新建sem.h,定义信号量的数据结构。

image-20220612134551189

sem.c

在linux-0.11/kernel目录下,新建实现信号量函数的源代码文件sem.c。

image-20220612134734941

修改unistd.h

在其中增加对于信号量的系统调用编号,类似于之前的操作

image-20220612135224839

修改system_call.s

因为增加了四个sem系统调用函数,在system_call.s文件中找到nr_system_calls并将其值更改为76

image-20220612135344070

修改sys.h

image-20220612140948110

image-20220612141013642

修改Makefile

image-20220612141105182

image-20220612141116701

准备文件

在oslab根目录下执行

1
sudo ./mount-hdc

使用cp命令将unistd.h复制到usr/include下,将sem.h复制到usr/include/linux下

编写程序

新建pc.c

image-20220612141444002

进行挂载,再,利用cp命令将其移动到usr/root目录下

编译

运行linux-0.11之后,首先编译pc.c,使用命令

1
gcc -o pc pc.c

随后运行pc,使用命令

1
./pc > sem_output

最终在虚拟环境内输入

1
sync

把修改的数据写入磁盘。

查看sem_output

首先挂载hdc,然后进入usr/root目录并在终端内执行

1
sudo less sem_output

命令,可看到下图结果:

image-20220612141711137

问题回答

如果去掉所有与信号量有关的代码,编译运行程序之后可以发现输出的数字顺序完全混乱。
信号量不存在的情况下,进程之间无法同步或者协作,造成此种情况的有如下原因:

1
2
3
- 一种情况是缓冲区满了,生产者还在写入数据,会造覆盖掉部分数据。
- 一种是缓冲区为空,消费者尝试读取数据,读到的数据是已输出的数据。
- 多个进程对文件缓冲区同时访问,造成了程序崩溃。