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.轻装出发,重载而行