实验三 进程的同步与进程通信(一)

/**复习前面linux的命令知识:
touch test.c //创建一个文件
vi test.c //打开文件
gcc test.c //编译test.c程序
./a.out //运行程序
/

实验目的

1、熟悉PV操作的实现原理。
2、了解进程间通信机制。熟悉信号量机制。使用信号量机制模拟实现PV操作,从而控制多个进程对共享资源的使用。

实验内容

1、使用信号量机制来模拟实现PV操作。

//sem_p.h
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<stdlib.h>
#include<stdio.h>

typedef union semun{
    
    
	int val;
	struct semid_ds *buf;
	unsigned short *array;
}semun;

//初始化信号量 
int sem_init(int key)
{
    
    
	int semid;
	semun arg;
	if((semid=semget(key,1,0660|IPC_CREAT|IPC_EXCL))<0) //创建包含 1 个信号量的信号量对象
	{
    
    
	perror("sem_init:semget error");
	exit(1);
	}

arg.val = 1;

if(semctl(semid,0,SETVAL,arg)<0)
{
    
    
	perror("sem_init:semctl error");
	exit(2);
};
	return semid;
}

//信号量的 P 操作
int sem_p(int semid)
{
    
    
	struct sembuf pbuf;
	pbuf.sem_num=0;
	pbuf.sem_op=-1;
	pbuf.sem_flg=SEM_UNDO;
	if(semop(semid,&pbuf,1)==-1)
	{
    
    
		perror("sem_p:semop error");
		exit(3);
	}
	return 0;
}

//信号量的 V 操作
int sem_v(int semid)
{
    
    
	struct sembuf vbuf;
	vbuf.sem_num=0;
	vbuf.sem_op=1;
	vbuf.sem_flg=SEM_UNDO;
	if(semop(semid,&vbuf,1)==-1)
	{
    
    
		perror("sem_v:semop error");
		exit(3);
	}
	return 0;
}

//删除信号量
void sem_rmv(int semid)
{
    
    
	if(semctl(semid,0,IPC_RMID)<-1)
	{
    
    
		perror("sem_rmv:semctl error");
		exit(2);
	}
}
//test.c
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/wait.h>
#include<string.h>
#include<stdio.h>
#include"sem_pv.h"

int main(void)
{
    
    
	key_t key;
	int pid,fd,semid,n;
	char str[80];
	
	key=ftok(".",5);
	semid=sem_init(key);
	fd=open("test.txt",O_RDWR|O_CREAT|O_TRUNC,0644);
	while((pid=fork())==-1); 
	if(pid==0)
	{
    
    
		sleep(1);
		sem_p(semid);
		lseek(fd,SEEK_SET,0);
		read(fd,str,sizeof(str));
		sem_v(semid);
		printf("child:read str from test file:%s\n",str);
		exit(0);
}
else
{
    
    
	sem_p(semid);
	printf("parent:please enter a str for test file(strlen<80):\n");
	gets(str);
	n=strlen(str);
	lseek(fd, SEEK_SET,0);
	write(fd,str,n);
	sem_v(semid);
	wait(0);
	close(fd);
	sem_rmv(semid);
	exit(0);
	}
}

运行结果:
在这里插入图片描述

2、编写一个简单的程序,使用该PV模拟操作控制多进程对共享资源的使用。

//源代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include<semaphore.h>

#define P sem_wait
#define V sem_post 
#define full_apple &fullA
#define full_orange &fullB
#define empty &empty_aha

sem_t fullA;
sem_t fullB;
sem_t empty_aha;
int num=0; 

void* Dad(void *p)
{
    
    
    while(num<10)
    {
    
     
        P(empty);  
	    num++;
        printf("老爸放了个苹果%d\n",num);
        V(full_apple);
    }
}


void* Dangter(void *p)
{
    
    
    while(num<10)
    {
    
    
        P(full_apple);
		num++;               
         printf("女儿吃了个苹果%d\n",num);
        V(empty);
    }
}

void* Mum(void *p)
{
    
    
    while(num<10)
    {
    
     
        P(empty);  
	    num++;
        printf("老妈放了个橘子%d\n",num);
        V(full_orange);
    }
}


void* Son(void *p)
{
    
    
    while(num<10)
    {
    
    
        P(full_orange);
		num++;               
        printf("儿子吃了个橘子%d\n",num);
        V(empty);
    }
}

int main()
{
    
      
    sem_init(full_apple, 0, 0);
    sem_init(full_orange, 0, 0);   
    sem_init(empty, 0, 1);
    pthread_t tid0;
    pthread_t tid1;
    pthread_t tid2;
    pthread_t tid3;
    pthread_create(&tid0, NULL, Dad, NULL);
    pthread_create(&tid1, NULL, Mum, NULL);
    pthread_create(&tid2, NULL, Son, NULL);
    pthread_create(&tid3, NULL, Dangter, NULL);
    getchar();
    pthread_exit(0);
    return 0;
}

运行结果:
在这里插入图片描述

思考题

1、参考程序中的sem_p (),sem_v()是原子操作吗?这种模拟能达到预期效果吗?它们与实验三中的lock()与unlock()有何异同?
答:是,可以达到预期的效果。Sem_p(),sem_v()程序不能中断,多个进程不能同时执行,一个信号量只能置一次初值,以后只能对其进行p操作或者操作,而这都可以达到进程互斥的目的。

2、请思考程序代码中sleep(1)的作用。
答:父进程先于子进程执行完毕,父进程执行完了之后子进程就会成为一个孤儿进程,孤儿进程由系统进行回收,所以它是不占用资源的。而如果让子进程先于父进程执行完成,那么子进程就会成为一个僵死进程,僵死进程会一直等待父进程的回收,但是如果父进程是一个循环,不会结束;那么子进程就会一直保持僵死状态,而僵死是占用系统列表中的资源的,假如系统中有大量的僵死进程存在,系统就会因缺乏资源而导致崩溃。Sleep(1)在这个地方的作用也是为了避免和防范僵死进程的产生。

猜你喜欢

转载自blog.csdn.net/Zheng_lan/article/details/109500707
今日推荐