MOOC哈工大操作系统实验5:信号量的实现和应用

1.写在前面:

本实验只完成了信号量的应用,即在linux下写了一个利用信号量解决生产者和消费者的程序。

实验提示中写到,在生产者进程和消费者进程中需要文件读写,我们可以通过标准C的库函数来实现,也可以直接通过对应的系统调用来实现。
在这里插入图片描述
如果通过系统调用来实现文件读写的话,文件头应该加上那3行定义的系统调用宏从而进入内核中使用对应的系统调用(像实验二系统调用中iam.c和whoami.c文件那样)。有同学是通过其它C库(非标准C库)来使用了read()、write()函数然后说是使用系统调用完成的。这不属于直接使用系统调用,本质上用的是库函数,只是库不是标准C库,然后库函数的名字跟系统调用名字一样而已。只有通过系统调用宏进入内核的方法才算是直接使用了系统调用,而无论使用标准C库还是其它C库,都是对系统调用的封装,不算是直接使用系统调用。

本文中使用的是标准C的库函数,要注意由于写函数fwrite()是将内容写到了进程空间内的文件缓冲区,父子进程是不共享这个缓冲区的,因此需要执行fflush()将数据更新到磁盘,才能让其他进程读到数据;printf()函数也需要fflush(一般写c程序的时候,只用printf(),加不加fflush(stdout)好像没什么区别,都是立即就显示出结果了,但是用fork()的时候效果就不一样了:在使用多个输出函数连续进行多次输出时,有可能发现输出错误,比如下一个数据在上一个数据还没输出完毕,还在输出缓冲区中时,下一个printf就把另一个数据加入输出缓冲区,结果冲掉了原来的数据,出现输出错误。 所以要在 prinf()后加上fflush(stdout); 强制马上输出,避免错误。)

关于文件读写的这3个函数的说明:
1.fseek():函数头如下,该函数的作用就是修改指向FILE文件类型的指针stream,即第一个参数stream。第二个参数offset是偏移量,以字节为单位。第三个参数whence有一些常量供选择,如SEEK_SET指从文件的开头位置来数的意思。
参考https://www.runoob.com/cprogramming/c-function-fseek.html

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

2.fread():函数头如下,该函数的作用是从stream指针指向的文件中,读取nmemb个元素,每个元素size个字节,将读到的内容放到ptr指向的地址处。
参考https://www.runoob.com/cprogramming/c-function-fread.html

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)fread(&productid,sizeof(int),1,fp) 就是从fp指向的文件中,读取一个int长度的元素,然后保存到productid变量中

3.fwrite():函数头如下,该函数的作用是向stream指针指向的文件中写入nmemb个元素,每个元素size个字节,写入的内容是ptr 指向的内容。
参考https://www.runoob.com/cprogramming/c-function-fwrite.html

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

2.开始写:

先声明一些需要用到的头文件和一些变量的初始化,定义要用到的宏,声明函数。(实际上本部分是在写代码的过程中用到了什么就加进来的,在这里先写出来是为了方便大家看后面代码的过程中可以清楚各个变量的意义)

#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/wait.h>
#define ALLNUM 550
#define CUSTOMERNUM 5
#define BUFFERSIZE 10
void Producters(FILE *fp);
void Customer(FILE *fp);
sem_t *empty,*full,*mutex;
FILE *fp;
int Inpos=0;
int Outpos=0;

生产者:
首先确定用什么样的数据结构来实现共享缓冲区,在这里用一个包含11个元素的数组来表示,前10个元素即0~9号用来存放生产者存放的数据,而最后一个元素有着特殊的作用,在之后消费者进程中会用到。

题目要求建立一个生产者进程,它存放数据是从0号位置开始,把0存在0号位置,然后把1存在1号位置、把2存在2号位置。。把9存到9号位置后再次轮转回来把10放到0号位置,把11放到1号位置。。。因此写一个循环,使要存入的数从0开始逐渐增加,那么存放的位置可以通过该数对缓冲区长度10取余数来得到。

void Producters(FILE *fp)
{
   
    int i=0;
    for (i=0;i<ALLNUM;i++)
    {
   
        sem_wait(empty);
        sem_wait(mutex);
        fseek( fp, Inpos * sizeof(
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值