计算机操作系统第五次实验——信号量实现进程同步
1.实验目的利用信号量和PV操作实现进程的同步。 2.实验软硬件环境安装Windows XP的计算机VirtualBox软件,以及在其上安装的Ubuntu虚拟机3.实验内容 生产者进程生产产品,消费者进程消费产品。当生产者进程生产产品时,如果没有空缓冲区(仓库)可用,那么生产进程必须等待消费者进程释放出一个缓冲区,当消费者进程消费产品时,如果缓冲区产品,那么消...
1.实验目的
利用信号量和PV操作实现进程的同步。
2.实验软硬件环境
- 安装Windows XP的计算机
- VirtualBox软件,以及在其上安装的Ubuntu虚拟机
3.实验内容
生产者进程生产产品,消费者进程消费产品。当生产者进程生产产品时,如果没有空缓冲区(仓库)可用,那么生产进程必须等待消费者进程释放出一个缓冲区,当消费者进程消费产品时,如果缓冲区产品,那么消费者进程将被阻塞,直到新的产品被生产出来。模拟一个生产者两个消费者的情况。
使用函数:
1 semget函数
它的作用是创建一个新信号量或取得一个已有信号量,原型为: int semget(key_t key, int num_sems, int sem_flags); semget函数成功返回一个相应信号标识符(非零),失败返回-1. 第一个参数key是整数值(唯一非零),不相关的进程可以通过它访问一个信号量,它代表程序可能要使用的某个资源,程序对所有信号量的访问都是间接的,程序先通过调用semget函数并提供一个键,再由系统生成一个相应的信号标识符(semget函数的返回值),只有semget函数才直接使用信号量键,所有其他的信号量函数使用由semget函数返回的信号量标识符。如果多个程序使用相同的key值,key将负责协调工作。 第二个参数num_sems指定需要的信号量数目,它的值几乎总是1。 第三个参数sem_flags是一组标志,当想要当信号量不存在时创建一个新的信号量,可以和值IPC_CREAT做按位或操作。设置了IPC_CREAT标志后,即使给出的键是一个已有信号量的键,也不会产生错误。而IPC_CREAT | IPC_EXCL则可以创建一个新的,唯一的信号量,如果信号量已存在,返回一个错误。 |
2 semop函数
它的作用是改变信号量的值,原型为: int semop(int sem_id, struct sembuf *sem_opa, size_tum_sem_ops); sem_id是由semget返回的信号量标识符,sembuf结构的定义如下: struct sembuf{ short sem_num;//除非使用一组信号量,否则它为0 short sem_op;//信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,P(等待)操作,一个是+1,即V(发送信号)操作。 short sem_flg;//通常为SEM_UNDO,使操作系统跟踪信号,并在进程没有释放该信号量而终止时,操作系统释放信号量 }; |
3 semctl函数
该函数用来直接控制信号量信息,它的原型为: int semctl(int sem_id, int sem_num, int command, ...); 如果有第四个参数,它通常是一个union semum结构,定义如下: union semun{ int val; struct semid_ds *buf; unsigned short *arry; }; 前两个参数与前面一个函数中的一样,command通常是下面两个值中的其中一个 SETVAL:用来把信号量初始化为一个已知的值。这个值通过union semun中的val成员设置,其作用是在信号量第一次使用前对它进行设置。 IPC_RMID:用于删除一个已经无需继续使用的信号量标识符。 |
4.实验程序及分析
实验程序:
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/sem.h>
#define KEY (key_t)14010322
union semun{
int val;
struct semid_ds *buf;
unsigned short *arry;
};
static int sem_id = 0;
static int set_semvalue();
static void del_semvalue();
static void semaphore_p();
static void semaphore_v();
int main(int argc, char *argv[])
{
//创建信号量,利用semget函数
//初始化信号量,利用semctl函数
int semid;
int product = 1;
int i;
if((semid = semget(KEY,3,IPC_CREAT|0660))==-1)
{
printf("ERROR\n");
return -1;
}
union semun arg[3];
arg[0].val = 1;//mutex = 1;
arg[1].val = 5;//empty = 5;
arg[2].val = 0;//full = 0;
for(i=0;i<3;i++)
{
semctl(semid,i,SETVAL,arg[i]);
}
for(i=0;i<3;i++)
{
printf("The semval(%d) = %d\n",i,semctl(semid,i,GETVAL,NULL));
}
pid_t p1,p2;
if((p1=fork())==0){
while(1){
//生产者……………..
semaphore_p(semid,1);//P(empty)
printf("1\n");
semaphore_p(semid,0);//P(mutex)
printf("2\n");
product++;
printf("Producer %d: %d things",getpid(),product);
semaphore_v(semid,0);//V(mutex);
semaphore_v(semid,2);//V(full);
sleep(2);
}
}else{
if((p2=fork())==0){
while(1){
sleep(2);
semaphore_p(semid,2);//p(full)
printf("3\n");
semaphore_p(semid,0);//p(mutex)
printf("4\n");
product--;
printf("Consumer1 %d: %d things",getpid(),product);
semaphore_v(semid,0);//v(mutex)
semaphore_v(semid,1);//v(empty)
sleep(5);
}
}
else{
while(1){
sleep(2);
semaphore_p(semid,2);//p(full)
printf("5\n");
semaphore_p(semid,0);//p(mutex)
printf("6\n");
product--;
printf("Consumer2 %d: %d things",getpid(),product);
semaphore_v(semid,0);//v(mutex)
semaphore_v(semid,1);//v(empty)
sleep(5);
}
}
}
}
static void del_semvalue()
{
//删除信号量
union semun sem_union;
if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
fprintf(stderr, "Failed to delete semaphore\n");
}
static int set_semvalue()
{
//用于初始化信号量,在使用信号量前必须这样做
union semun sem_union;
sem_union.val = 1;
if(semctl(sem_id, 0, SETVAL, sem_union) == -1)
return 0;
return 1;
}
void semaphore_p(int sem_id,int semNum)
{
//对信号量做减1操作,即等待P(sv)
struct sembuf sem_b;
sem_b.sem_num = semNum;
sem_b.sem_op = -1;//P()
sem_b.sem_flg = SEM_UNDO;
// semop(semid,&sem_b,1);
if(semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_p failed\n");
return;
}
return;
}
void semaphore_v(int sem_id,int semNum)
{
//这是一个释放操作,它使信号量变为可用,即发送信号V(sv)
struct sembuf sem_b;
sem_b.sem_num = semNum;
sem_b.sem_op = 1;//V()
sem_b.sem_flg = SEM_UNDO;
// semop(semid,&sem_b,1);
if(semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_p failed\n");
return;
}
return ;
}
分析:
定义3个信号量,full,empty,mutex,分别表示产品个数,缓冲区空位个数,对缓冲区进行操作的互斥信号量,对应的初始化值分别为0,5,1。
生产者:
P(empty)---->P(mutex)----->V(mutex)----->V(full)
消费者:
P(full)----->P(mutex)------->V(mutex)------->V(empty)
由此实现了缓冲区为5,一个生产者和两个消费者的同步。
5.实验截图
6.实验心得体会
此次实验利用信号量实现了进程同步。其中用 semop函数具体实现了PV操作函数,并实现了一个生产者和两个消费者之间的同步。
更多推荐
所有评论(0)