OS实验三 共享内存与进程同步

简单了解共享内存: http://lobert.iteye.com/blog/1746041

1 实验目的与要求

1、掌握Linux下共享内存的概念与使用方法;

2、掌握环形缓冲的结构与使用方法;

3、掌握Linux下进程同步与通信的主要机制。

实验内容

利用多个共享内存(有限空间)构成的环形缓冲,将源文件复制到目标文件,实现两个进程的誊抄。

3 实验过程与结果

实验过程:

(1)父进程使用shmget创建五个缓冲区,使用shmat挂接到父进程并形成环状缓冲区;

(2)父进程创建两个信号灯w和r,对信号灯赋初值(w为5,代表可写缓冲区数量;r为0,代表可读缓冲区数量);

(3)父进程创建子进程1和、子进程2。其中子进程1把源文件数据向缓冲区写入数据,子进程2则把缓冲区数据写入目标文件。

(4)通过对信号量的PV操作使子进程同步运行,同时,当写入目标文件的速度追上从源文件读出速度时,写操作应等待读操作。

(5)读到文件尾,将最后一次读出的字节数赋给结束标志,最后一次写入目标文件的字节数与此相等,确保誊抄正确。

(6)子进程誊写结束后,父进程删除信号量与共享缓冲区后,打印删除成功的提示信息,进程结束,

4、实验代码

#include  
#include  
#include  
#include   
#include  
#include 
#include 
#include 
#include 
#include 

#define BLOCK_SIZES 5 //缓冲区个数
#define BUFFER_SIZE 1024 //缓冲区大小

union semun {
    int val; /* value for SETVAL */
    struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
    unsigned short *array; /* array for GETALL, SETALL */
    struct seminfo *__buf; /* buffer for IPC_INFO */
    };
union semun arg;
int semid;//信号量集合首地址
struct share_buffer  
{
	int end;  
    char buffer[BUFFER_SIZE];
	struct share_buffer *next;
};  
struct share_buffer *start=NULL;
  
char *share[BLOCK_SIZES];//指向共享缓冲区
int pid1,pid2;//子进程标识符
int running=1;
int shmid[BLOCK_SIZES];//共享缓冲区标识符  

/***对信号量数组index编号的信号量做P操作***/
void P(int semid, int index){
	struct sembuf sem={index,-1,0};
    semop(semid,&sem,1);
}

/***对信号量数组index编号的信号量做V操作***/
void V(int semid, int index){
    struct sembuf sem={index,+1,0};
    semop(semid,&sem,1);
}

void writebuf()
{
    int file_end;
	int times=0;
	const char* pathname;
	struct share_buffer *in=start;  
	int fd;//文件描述符  
	char pn[100]="/home/kuixiao/aaa";  
	pathname=pn; 
	if ((fd=open(pathname,O_RDONLY))==-1){
		printf("打开源文件失败\n");
		return;
	}
	else
		printf("打开源文件成功\n");
	while(running){
		P(semid,0);
		file_end=read(fd,in->buffer, BUFFER_SIZE-1);
		if(file_end!=BUFFER_SIZE-1&&file_end!=0){
			printf("最后一次从源文件读出%d字节\n",file_end);
			in->end=file_end;
			V(semid,1);
			return;
		}			
		printf("第%d次从源文件读出\n",++times);			
		in=in->next;
		V(semid,1);
	}
	exit(EXIT_SUCCESS);
}

void readbuf()
{
	int times=0;
	const char* pathname;
	struct share_buffer *out=start;  
	int fd;//文件描述符  
	char pn[100]="/home/kuixiao/ccdd";  
	pathname=pn; 
	if ((fd=open(pathname,O_WRONLY|O_CREAT,S_IRWXU|S_IXGRP|S_IROTH|S_IXOTH))==-1){
		printf("打开目标文件失败");
		return;
	}
	else
		printf("打开目标文件成功\n");
	while(running){	
		P(semid,1);	
		write(fd,out->buffer, BUFFER_SIZE-1);
		printf("第%d次写入到目标文件\n",++times);	
		out=out->next;
		V(semid,0);
		if(out->end!=0)//写到文件尾
		{
			printf("最后一次写入%d个字节到目标文件\n",out->end);
			write(fd,out->buffer,out->end);			
		 	return ;
		}
	}
	exit(EXIT_SUCCESS);
}
int main()  
{  
	int ret;	
	int i;  
	void* shm=NULL; 
	key_t key=1234,key1;
	struct share_buffer *head=NULL,*tail=NULL; 
	int size=sizeof(struct share_buffer);
	/***创建共享内存组***/
	for(i=0;iend=0;
		head->next=tail;
		if(i==0)start=head;	
		tail=head;
	}
	start->next=head;
	/***获得键值***/
	key1=ftok("/tmp", 0x66 ) ;
    if(key<0){
        perror("ftok key error") ;
        return -1 ;
    }
    /***创建两个信号量***/
    semid=semget(key,2,IPC_CREAT|0666);
    if(semid==-1){
         perror("create semget error");
         return ;
    }
    /***对两个信号量赋初值***/
	arg.val=BLOCK_SIZES;
    ret=semctl(semid,0,SETVAL,arg);//信号量semid【0】为1
	arg.val=0;
	ret =semctl(semid,1,SETVAL,arg);//信号量semid【1】为0
    if (ret < 0 ){
        perror("ctl sem error");
        semctl(semid,0,IPC_RMID,arg);
        return -1 ;
    }
	/***创建子进程***/
	 if((pid1=fork())<0){
            perror("Fail to fork");
            exit(EXIT_FAILURE);
        }
	else if(pid1==0)writebuf();
 	else {
		if((pid2=fork())<0){
			perror("Fail to fork");
			exit(EXIT_FAILURE);
		}
		else if(pid2==0)readbuf();
		else
		{
			/***等待子进程结束***/
			waitpid(pid1,NULL,0);
			waitpid(pid2,NULL,0);
			printf("子进程已结束\n");
			/***删除信号量***/
			semctl(semid,0,IPC_RMID,arg);
			semctl(semid,1,IPC_RMID,arg);
			printf("信号量删除成功\n");  
			/***删除缓冲区***/
			for(i=0;i

 

你可能感兴趣的:(操作系统)