共享内存
所有函数所需的头文件请用man手册查阅,这里都不写了
使用共享内存步骤:
① 开辟一块共享内存shmget
② 允许本进程使用共某块共享内存shmat
③ 写入/读取
删除共享内存步骤
①禁止本进程使用这块共享内存shmdt
②删除这块共享内存shmctl或者命令行下ipcrm
1、创建共享内存
任务描述:
- 使用shmget函数创建共享内存,并输出创建的shmid
- 判断创建的shmid是否成功,失败返回-1,成功打印共享内存的id号
相关知识:
共享内存函数由 shmget、shmat、shmdt、shmctl 四个函数组成。
①shmget函数
作用:得到一个共享内存标识符或创建一个共享内存对象
原型:int shmget(key_t key, size_t size, int shmflg)
②shamat函数
作用:连接共享内存标识符为 shmid 的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问
原型:void *shmat(int shmid, const void *shmaddr, int shmflg)
③shmdt函数
作用:断开与共享内存附加点的地址,禁止本进程访问此片共享内存
原型:int shmdt(const void *shmaddr)
④shmctl函数
作用:完成对共享内存的控制
原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf)
main.c:
#include <stdio.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <error.h>
#define SIZE 1024
int main(void)
{
int shmid ;
shmid=shmget(IPC_PRIVATE,512,IPC_CREAT|0600 ) ;
if ( shmid < 0 ){
perror("get shm ipc_id error") ;
return -1 ;
}
printf("shmid=%d\n",shmid) ;
return 0 ;
}
2、使用fork函数创建子进程
任务描述:
- 在task1基础上使用fork创建子进程
- 在子进程中打印"this is child",在父进程中打印"this is parent"
main.c:
#include <stdio.h> #include <unistd.h> #include <sys/ipc.h> #include <sys/shm.h> #include <error.h> int main(void) { int shmid; struct shmid_ds buf; shmid=shmget(IPC_PRIVATE,512,IPC_CREAT|0600 ) ; if ( shmid < 0 ){ perror("get shm ipc_id error") ; return -1 ; } printf("shmid is %d\n",shmid); pid_t pid; pid=fork(); if(pid<0){ perror("fork error\n"); shmctl(shmid,IPC_RMID,&buf); } if(pid==0) printf("this is child\n"); else printf("this is parent\n"); return 0 ; }
3、在子进程中将键盘输入字符串写入共享内存
任务描述:
- 在task2的基础上在子进程中使用shmat函数与共享内存空间建立联系
- 将共享内存映射到子进程中,将参数字符串拷贝到共享内存中.
- 拷贝完毕后使用shmdt函数分离共享内存对象
main.c:
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/ipc.h> #include<sys/shm.h> #include<error.h> #include<string.h> int main(void) { int shmid;char x[10]; struct shmid_ds buf; char *shmaddr; shmid=shmget(IPC_PRIVATE,512,IPC_CREAT|0600 ) ; if ( shmid < 0 ){ perror("get shm ipc_id error\n") ; return -1 ; } printf("shmid is %d\n",shmid); pid_t pid; pid=fork(); if(pid<0){ perror("fork error\n"); shmctl(shmid,IPC_RMID,&buf); } if(pid==0){ printf("this is child\n"); shmaddr=(char *)shmat(shmid,NULL,0); if(shmaddr<(char *)0){ perror("shmat addr error\n"); return -1; } printf("write something to shm\n"); fgets(x,11,stdin); strcpy(shmaddr,x); // printf("%s\n",shmaddr); shmdt(shmaddr); return 0; }else{ wait(); printf("this is parent\n"); shmaddr=(char *)shmat(shmid,NULL,0); printf("%s\n",shmaddr); } return 0 ; }
4、打印共享内存大小和子进程、父进程进程号
任务描述:
- 基于task3,在父进程中打印共享内存大小以及父进程的进程号和子进程的进程号
main.c:
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/ipc.h> #include<sys/shm.h> #include<error.h> #include<string.h> int main(void) { int shmid;char x[10]; struct shmid_ds buf; char *shmaddr; shmid=shmget(IPC_PRIVATE,512,IPC_CREAT|0600 ) ; if ( shmid < 0 ){ perror("get shm ipc_id error\n") ; return -1 ; } //printf("shmid is %d\n",shmid); pid_t pid; pid=fork(); if(pid<0){ perror("fork error\n"); shmctl(shmid,IPC_RMID,&buf); } if(pid==0){ printf("this is child\n"); printf("child pid is %d\n",getpid()); //shmaddr=(char *)shmat(shmid,NULL,0); // if(shmaddr<(char *)0) // { // perror("shmat addr error\n"); //return -1; //} //printf("write something to shm\n"); //fgets(x,11,stdin); //strcpy(shmaddr,"your input string is'xxx'\n"); //shmdt(shmaddr); return 0; } else{ //memset(&buf,'\0',sizeof(buf)); //wait(); //printf("%s\n",shmaddr); shmctl(shmid,IPC_STAT,&buf); printf("The size of new buf is %ld bytes\n",buf.shm_segsz); printf("this is parent\n"); printf("parent pid is %d\n",getpid()); } return 0 ; }
5、两个进程通过共享内存通信
任务描述:
- 编写两个.c文件,分别完成将图书信息写入共享内存以及从共享内存读取图书信息的功能
- 图书信息(no;name;price)使用结构体定义
- 01 book1 10
- 02 book2 20
- read.c中读取完毕要删除共享内存
- write,c中每次都新建共享内存
- ftok
写程序:
- 实现父子进程通过共享内存进行数据通信.
- 父子进程通过竞争方式来创建一个共享内存单元,然后子进程接受用户输入的信息(键盘输入),并将写入到共享内存单元;父进程则从共享内存单元将该信息读出,并显示信息的个数,具体步骤为:创建子进程->将输入的字符串写入共享内存->打印写入的字符串->在父进程中读取写入的字符串并打印
write.c:
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/ipc.h> #include<sys/shm.h> #include<error.h> #include<string.h> #include<sys/types.h> typedef struct book { int num; char name[20]; float price; }book; int main(void) { int shmid,i; key_t key; book *shmaddr; char temp[20]; key=ftok("write.c",0x03); if(key==-1){ perror("key error\n"); return -1; } printf("key=%d\n",key); shmid=shmget(key,512,IPC_CREAT|0600 ) ; if (shmid<0){ perror("shmid get error\n") ; return -1 ; } else{ printf("shmid =%d\n",shmid); shmaddr=(book *)shmat(shmid,NULL,0); if(shmaddr<(book *)0){ perror("shmat addr error\n"); return -1; } memset(temp,0x00,sizeof(temp)); strcpy(temp,"book"); temp[4]='0'; for(i=0;i<2;i++){ temp[4]+=1; strcpy((shmaddr+i) -> name,temp); (shmaddr+i) -> num=i; (shmaddr+i)->price=10*(i+1); } shmdt(shmaddr); } return 0 ; }
读程序:
- 采用shmat函数取得对共享内存空间的地址
- 打印共享内存中的字符串
- 使用shmdt函数取消父进程与共享内存的关联
- 使用shmctl函数删除共享内存
read.c:
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/ipc.h> #include<sys/shm.h> #include<error.h> #include<string.h> #include<sys/types.h> typedef struct book { int num; char name[20]; float price; }book; int main(void) { int shmid,i; char temp[20]; key_t key; book *shmaddr; key=ftok("write.c",0x03); if(key==-1){ perror("key error\n"); return -1; } printf("key=%d\n",key); shmid=shmget(key,512,IPC_CREAT|0600 ) ; if (shmid<0){ perror("shmid get error\n") ; return -1 ; } else{ printf("shmid =%d\n",shmid); shmaddr=(book *)shmat(shmid,NULL,0); if(shmaddr<(book *)0){ perror("shmat addr error\n"); return -1; } for(i=0;i<2;i++){ printf("num:%d,",(*(shmaddr+i)).num); printf("name:%s,",(*(shmaddr+i)).name); printf("price:%f\n",(*(shmaddr+i)).price); } shmdt(shmaddr); } return 0 ; }
6、无名管道
任务描述:
- 创建管道,父进程接受键盘输入,将其写入管道,子进程读取管道,将读取到的字符串打印出来
相关知识:
管道是一种把两个进程之间的标准输入和标准输出连接起来的机制,从而提供一种让多个进程间通信的方法,当进程创建管道时,每次都需要提供两个文件描述符来操作管道。其中一个对管道进行写操作,另一个对管道进行读操作。对管道的读写与一般的IO系统函数一致,使用write()函数写入数据,使用read()读出数据。
必须在fork()中调用pipe(),否则子进程不会继承文件描述符。两个进程不共享祖先进程,就不能使用pipe。但是可以使用命名管道。
main.c:
#include <unistd.h> #include <stdio.h> #define size 100 int main(void) { int filedes[2]; char a[size],b[size]; pid_t pid; pipe(filedes); pid=fork(); if(pid<0){ printf("pid error\n"); return 0; } if (pid > 0){ printf( "This is father process\n"); printf("please input something and wait a little time\n"); fgets(a,50,stdin); printf("write pipe:%s\n",a); write( filedes[1],a,sizeof(a)); close( filedes[0] ); close( filedes[1] ); } else if(pid == 0){ sleep(7); printf("This is child process.\n"); read( filedes[0], b, sizeof(b)); printf( "read pipe: %s\n", b ); close( filedes[0] ); close( filedes[1] ); } waitpid( pid, NULL, 0 ); return 0; }