ZUCC_操作系统实验_Lab7进程通信---共享内存

lab7进程通信—共享内存

一.利用共享内存实现生产者/消费者问题的解决方案

1.代码

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<sys/ipc.h>
#include<sys/shm.h>

#define KEY 1234		//键
#define SIZE 1024		//欲建立共享内存的大小

int main(){
	int shmid;
	char *shmaddr;
	struct shmid_ds buf;	
	shmid=shmget(KEY,SIZE,IPC_CREAT|0600);		//建立共享内存
	
	if(shmid==-1){
		printf("create share memory failed:%s",strerror(errno));
		return 0;
	}
	if(fork()==0){
		sleep(2);							//子进程
		shmaddr=(char*)shmat(shmid,NULL,0);//系统自动选择一个地址来链接
		if(shmaddr==(void*)-1){
			printf("connect the share memory failed:%s",strerror(errno));
			return 0;
		}
		strcpy(shmaddr,"heelo i am huij\n");
		shmdt(shmaddr);			//断开共享内存
		exit(0);
	}
	else{
		wait(0);					//父进程
		shmctl(shmid,IPC_STAT,&buf);	//获取共享内存相关信息
		printf("size of the share memory:shm_segsz=%dbytes\n",buf.shm_segsz);
		printf("process id of the creator:shm_cpid=%d\n",buf.shm_cpid);
		printf("process id of the last operator:shm_lpid=%d\n",buf.shm_lpid);
		shmaddr=(char*)shmat(shmid,NULL,0);//系统自动选择一个地址连接
		if(shmaddr==(void*)-1){
			printf("connect the share memory failed:%s",strerror(errno));
			return 0; 
		}
		printf("print the content of the share memory:\t");
		printf("%s\n",shmaddr);
		shmdt(shmaddr);				//断开共享内存
		shmctl(shmid,IPC_STAT,&buf);//取得共享内存相关信息
		printf("process id of the last operator:shm_lpid =%d\n",buf.shm_lpid);
		//当不在有任何其他相关进程使用该共享内存时系统自动销毁它
		shmctl(shmid,IPC_RMID,NULL);
	}
} 

运行注意:

1. ./t &
2. ctr+c 

2)删除注释1,重新编译运行程序,理解变和不变的部分

1.不删注释1:[1]+ 完成				ipcs -m -t:无最新共享内存信息
  删除注释1:[1]+ 退出  47			ipcs -m -t:有最新共享内存消息

不删注释:

删除注释:

3)删除注释1,重新编译运行程序,利用ipcs查看共享内存的相关信息

删除注释:



二.利用共享内存机制,在两个并发程序中,传递数据

1.代码:

//write.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/shm.h>
#include<sys/ipc.h>

#define SHMSZ 27

int main(){
	char c;
	int shmid;
	key_t key;
	char *s,*shm;
	key=5679;
	if((shmid=shmget(key,SHMSZ,IPC_CREAT|0666))<0){
		perror("shmget");
		exit(1);
	}
	if((shm=shmat(shmid,NULL,0))==(char*)-1){
		perror("shmat");
		exit(1);
	}
	s=shm;
	for(c='a';c<'z';c++){
		*s++=c;
//		sleep(1);
	}
	*s='\0';
} 
//read.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/ipc.h>
#include<sys/shm.h>

#define SHMSZ 27

int main(){
	int shmid;
	key_t key;
	char *s,*shm;
	key=5679;
	
	if((shmid=shmget(key,SHMSZ,0666))<0){			//
		perror("shmget");				//
		exit(1);
	}
	if((shm=shmat(shmid,NULL,0))==(char*)-1){			//
		perror("shmat");	
		exit(1);
	}
	for(s=shm;*s!='\0';s++)
		putchar(*s);
	putchar('\n');					///''  (x:"")
	exit(0);
}

通过两个终端分别运行写入进程和读出进程,观察进程并发执行结果:

注意:1.在运行读和写程序后要清理共享内存
	 2.清理的方式:ipcs -m -t  获得共享内存的信息
	 			 ipcrm  -m shmid  删除该共享内存信息 

2)两个并发进程的启动顺序对程序运行有没有影响?

有影响,先写再读才有输入结果嘛

先写再读:

先读再写:

注意:因为程序没有配置删除共享内存代码,所以需要手动删除
1.ipcs -m -t
2.ipcrm -m shmid (删除最近时间创立的几个)

3)将注释1换成{*s++=c;sleep(1)),降低写入进程写数据的速度,观察对读出进程的影响?这说明共享内存没有提供同步机制,有可能导致数据缺失

注意:因为程序没有配置删除共享内存代码,所以需要手动删除
1.ipcs -m -t
2.ipcrm -m shmid (删除最近时间创立的几个)
3. ./writer(另一个终端)
4. ./reader(另一个终端)

如图:



三.利用共享内存实现生产者/消费者问题

1.代码:

//The second program is the producer and allow us to enter data for consumers
 #include<stdio.h>
 #include<stdlib.h>
 #include<string.h>
 #include<unistd.h>
 #include<sys/types.h>
 #include<sys/ipc.h>
 #include<sys/shm.h>
 
 #define TEXT_SZ 2048
 
 struct shared_use_st{
 	int written_by_you;
 	char some_text[TEXT_SZ];
 };
 
 int main(){
 	int running=1;
 	void *shared_memory=(void*)0;
 	struct shared_use_st *shared_stuff;
 	char buffer[BUFSIZ];
 	int shmid;
 	
 	shmid=shmget((key_t)1234,sizeof(struct shared_use_st),0666|IPC_CREAT);		//
 	if(shmid==-1){
 		fprintf(stderr,"shmget failed\n");
 		exit(EXIT_FAILURE);
	}
	shared_memory=shmat(shmid,(void*)0,0);		//
	if(shared_memory==(void*)-1){
		fprintf(stderr,"shmat failed\n");
		exit(EXIT_FAILURE);
	} 
	shared_stuff=(struct shared_use_st*)shared_memory;		//
	while(running){
//		while(shared_stuff->written_by_you==1){
//			sleep(1);
//			printf("waiting for client...\n");
//		}
		printf("Enter som text:");
		fgets(buffer,BUFSIZ,stdin);
		strncpy(shared_stuff->some_text,buffer,TEXT_SZ);
		shared_stuff->written_by_you=1;
		if(strncmp(buffer,"end",3)==0)			//
			running=0;
	} 
	if(shmdt(shared_memory)==-1){				//
		fprintf(stderr,"shmdt failed\n");		//
		exit(EXIT_FAILURE);			//
	}
	exit(EXIT_SUCCESS);			//
 }
/*Our first program is a consumer. After the header the shared memory segment (the size of our shared memory struct )is created with a call to shmget,with the IPC_CREAT nbit specified*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
 
#define TEXT_SZ 2048
 
struct shared_use_st{
 	int written_by_you;
 	char some_text[TEXT_SZ];
};
 
int main(){
 	int running=1;
 	void *shared_memory=(void*)0;
 	struct shared_use_st *shared_stuff;
 	int shmid;

	srand((unsigned int )getpid()); 	
 	shmid=shmget((key_t)1234,sizeof(struct shared_use_st),0666|IPC_CREAT);
 	if(shmid==-1){
 		fprintf(stderr,"shmget failed\n");
 		exit(EXIT_FAILURE);
	}
	
//We now make the shared memory accessible to the program
	shared_memory=shmat(shmid,(void*)0,0);
	if(shared_memory==(void*)-1){
		fprintf(stderr,"shmat failed\n");
		exit(EXIT_FAILURE);
	} 
	
/*The next portin of the program assigns the share_memory segment to shared_stuff,which then prints out any text in written_by_you.The loop continues until end is found in written_by_you.The call to sleep forces the consumer to sit in its critical section,which makes the producer wait*/	
	
	shared_stuff=(struct shared_use_st*)shared_memory;
	shared_stuff->written_by_you=0;
	while(running){
		if(shared_stuff->written_by_you){
			printf("You wrote:%s",shared_stuff->some_text);
			sleep(rand()%4);
			shared_stuff->written_by_you=0;
			if(strncmp(shared_stuff->some_text,"end",3)==0)
				running=0;
		}
	}
	
//Lastly,the shared memory is detached and then deleted	
	if(shmdt(shared_memory)==-1){
		fprintf(stderr,"shmdt failed\n");
		exit(EXIT_FAILURE);
	}
	if(shmctl(shmid,IPC_RMID,0)==-1){
		fprintf(stderr,"shmctl(IPC_RMID)failed\n");
		exit(EXIT_FAILURE);
	}
	exit(EXIT_SUCCESS);
 }

编译链接后,分别通过两个终端运行生产者,消费者进程,观察执行结果

2)确定两个并发进程的启动顺序

先消费,再生产
shared_stuff->written_by_you=0;在消费者中初始化

3)删除蓝色标记的代码,看对并发进程有什么影响?

1.write端“Enter some text""waiting for client"无输出

4)理解share_stuff->written_by_you在并发程序中的作用,效果如何?效率如何?

条件判断:等待消费者消费前生产者一直输出"waiting for client"


四.编写程序

1.编写程序,实现父进程和子进程通过共享内存交换信息。要求:子进程先将子进程号写入共享内存,父进程将内容读出并显示。随后,父进程将父进程号写入共享内存,子进程读出并显示。使用完毕,父进程注销共享内存。

代码:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<sys/ipc.h>
#include<sys/shm.h>

#define KEY 1234		//键
#define SIZE 1024		//欲建立共享内存的大小

void intToString(int a,char b[]){
	int i,m;
	char c[20];
	for(i=1;a/i!=0;i*=10);
	m=i/10;
//		printf("m %d\n",m);
	
	for(i=0;m!=0;i++,m/=10){
		c[i]=(char)(48+a/m);		//ASCll码 
		a-=a/m*m;	
	}
	c[i+1]='\0';
//		printf("%s\n",c);

	for(i=0;c[i]!='\0';i++)
		b[i]=c[i];	
} 
 
int main(){
	int shmid;
	char *shmaddr;
	int p1;
	struct shmid_ds buf;	
	shmid=shmget(KEY,SIZE,IPC_CREAT|0600);		//建立共享内存
	
	if(shmid==-1){
		printf("create share memory failed:%s",strerror(errno));
		return 0;
	}
	if((p1=fork())==0){
//		sleep(2);							//子进程
		shmaddr=(char*)shmat(shmid,NULL,0);//系统自动选择一个地址来链接
		if(shmaddr==(void*)-1){
			printf("connect the share memory failed:%s",strerror(errno));
			return 0;
		}
		char s[20];
		intToString(getpid(),s); 
		strcpy(shmaddr,s);
		sleep(1);
		
		printf("son pid is %d\n",getpid());
		printf("son get the parent's pid %s\n",shmaddr);
		shmdt(shmaddr);			//断开共享内存
		exit(0);
	}
	else{

		sleep(1);
		shmctl(shmid,IPC_STAT,&buf);	//获取共享内存相关信息
		shmaddr=(char*)shmat(shmid,NULL,0);//系统自动选择一个地址连接
		if(shmaddr==(void*)-1){
			printf("connect the share memory failed:%s",strerror(errno));
			return 0; 
		}
		printf("parent pid is %d\n",getpid());
		printf("parent get the son's pid %s\n",shmaddr);
			
		char t[20];
		strcpy(shmaddr,t);				//将shmadr内容置'\0' 
		intToString(getpid(),t); 
		strcpy(shmaddr,t);
		sleep(1);
		
		shmdt(shmaddr);				//断开共享内存
		shmctl(shmid,IPC_STAT,&buf);//取得共享内存相关信息
		//当不在有任何其他相关进程使用该共享内存时系统自动销毁它
		shmctl(shmid,IPC_RMID,NULL);
	}
} 
//1.注意:sleep(1)和wait(0)对父子进程的交替操作

如图:

问题:
1.t.c:(.text+0x139):对‘sterror’未定义的引用?
2.c语言怎么将整型转化为字符串? 自定义函数:找到最大十进制,依次除并ascall码表示
3.怎么让父子进程共享同一块内存,并相互存取,读取不干涉?

心得:1.轻装出发,重载而行

信号量是一种用于进程间通信和同步的机制。它是一个计数器,用于保证在共享资源上的互斥访问。在Linux系统中,可以使用信号量来实现进程间的同步和互斥。以下是信号量的基本概念: - 计数器:信号量的值是一个计数器,它可以被多个进程共享。 - P操作:当一个进程需要访问共享资源时,它必须执行P操作,该操作会将信号量的值减1。如果信号量的值为0,则进程将被阻塞,直到信号量的值大于0。 - V操作:当一个进程使用完共享资源后,它必须执行V操作,该操作会将信号量的值加1。如果有进程正在等待该信号量,则唤醒其中一个进程继续执行。 在ZUCC中,可以使用信号量来实现进程的同步和互斥。首先,需要使用semget函数创建一个信号量集合,并使用semctl函数对信号量进行初始化。然后,可以使用semop函数执行P和V操作。例如,下面是一个简单的示例程序,用于演示信号量的使用: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/sem.h> #define SEM_KEY 1234 union semun { int val; struct semid_ds *buf; unsigned short *array; }; int main() { int semid, pid; union semun arg; struct sembuf sb; // 创建信号量集合 semid = semget(SEM_KEY, 1, IPC_CREAT | 0666); if (semid == -1) { perror("semget"); exit(EXIT_FAILURE); } // 初始化信号量 arg.val = 1; if (semctl(semid, 0, SETVAL, arg) == -1) { perror("semctl"); exit(EXIT_FAILURE); } // 创建子进程 pid = fork(); if (pid == -1) { perror("fork"); exit(EXIT_FAILURE); } else if (pid == 0) { // 子进程执行P操作 sb.sem_num = 0; sb.sem_op = -1; sb.sem_flg = SEM_UNDO; if (semop(semid, &sb, 1) == -1) { perror("semop P"); exit(EXIT_FAILURE); } printf("Child process\n"); // 子进程执行V操作 sb.sem_num = 0; sb.sem_op = 1; sb.sem_flg = SEM_UNDO; if (semop(semid, &sb, 1) == -1) { perror("semop V"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } else { // 父进程执行P操作 sb.sem_num = 0; sb.sem_op = -1; sb.sem_flg = SEM_UNDO; if (semop(semid, &sb, 1) == -1) { perror("semop P"); exit(EXIT_FAILURE); } printf("Parent process\n"); // 父进程执行V操作 sb.sem_num = 0; sb.sem_op = 1; sb.sem_flg = SEM_UNDO; if (semop(semid, &sb, 1) == -1) { perror("semop V"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } return 0; } ``` 在上述代码中,创建了一个信号量集合,并将其初始化为1。然后,创建了一个子进程和一个父进程,它们分别执行P和V操作。由于信号量的初始值为1,因此父进程和子进程都可以顺利地执行。如果将信号量的初始值改为0,那么父进程和子进程都将被阻塞,直到有一个进程执行V操作为止。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值