共享内存进程间通信机制主要用于实现进程间大量的数据传输。
1 创建共享内存
#include <sys/ipc.h> #include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
2 共享内存控制
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
3 映射共享内存对象
void *shmat(int shmid, const void *shmaddr, int shmflg);
4分离共享内存对象
int shmdt(const void *shmaddr);
实例一
父子进程通过共享内存通信
#include<errno.h> #include<fcntl.h> #include<stdio.h> #include<string.h> #include<unistd.h> #include<sys/shm.h> #include<sys/wait.h> #include<stdlib.h> int main(int argc,char* argv[]) { int childpid; int id; int i; int buf[10]; char* ptr; int totalbytes = 0; key_t key; key = ftok("tmp",3); if((childpid = fork()) == -1) { perror("fork"); exit(EXIT_FAILURE); } if(childpid == 0) { //notice permission if((id = shmget(key,20*sizeof(char),0666|IPC_CREAT)) == -1) { perror("failed to create shared memory segment"); exit(EXIT_FAILURE); } if((ptr = (char*)shmat(id,0,0)) == NULL) { if(shmctl(id,IPC_RMID,NULL) == -1) perror("failed to remove memory segment"); exit(EXIT_FAILURE); } for(i=0;argv[1][i]!='\0';i++) { *ptr = argv[1][i]; ptr++; } printf("this is child.\nwrite argv[1] to shm.\nyou input charater count is %d\n",i); exit(EXIT_SUCCESS); } else { wait(NULL); if((id = shmget(key,10*sizeof(char),0666|IPC_CREAT)) == -1) { perror("shmget"); exit(EXIT_FAILURE); } if((ptr = (char*)shmat(id,0,0)) == NULL) { perror("shmat"); if(shmctl(id,IPC_RMID,NULL) == -1) perror("failed to remove memory segment"); exit(EXIT_FAILURE); } printf("this is parent.\ninput character is %s\n",ptr); if(shmctl(id,IPC_RMID,NULL) == -1) { perror("failed to remove memory segment"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } }
实例二
两个进程通过共享内存通信
同时,使用信号量来保证两个进程的读写同步。
发送方程序如下
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<sys/shm.h> #include<sys/ipc.h> #include<sys/sem.h> #include<string.h> int main(int argc,char* argv[]) { int running = 1; int shid; int semid; int value; void *sharem = NULL; struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_flg = SEM_UNDO; key_t key; key = ftok("tmp",3); if((semid = semget(key,1,0666|IPC_CREAT)) == -1) { perror("semget"); exit(EXIT_FAILURE); } if(semctl(semid,0,SETVAL,0) == -1) { printf("sem init error"); if(semctl(semid,0,IPC_RMID,0) != 0) { perror("semctl"); exit(EXIT_FAILURE); } exit(EXIT_FAILURE); } key_t key1; key1 = ftok("tmp2",4); shid = shmget(key1,10*sizeof(char),0600|IPC_CREAT); if(shid == -1) { perror("shmget"); exit(EXIT_FAILURE); } sharem = shmat(shid,NULL,0); if(sharem == NULL) { perror("shmat"); exit(EXIT_FAILURE); } while(running) { if((value = semctl(semid,0,GETVAL)) == 0) { printf("write data operate\n"); printf("please input charater:"); scanf("%s",sharem); sem_b.sem_op = 1; if(semop(semid,&sem_b,1) == -1) { fprintf(stderr,"semaphore_p failed\n"); exit(EXIT_FAILURE); } } if(strcmp(sharem,"end") == 0) running--; } shmdt(sharem); return 0; }
接收方程序如下
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<sys/shm.h> #include<sys/ipc.h> #include<sys/sem.h> #include<string.h> int main(int argc,char* argv[]) { int running = 1; int shid; int semid; int value; void *sharem = NULL; struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_flg = SEM_UNDO; key_t key; key = ftok("tmp",3); if((semid = semget(key,1,0666|IPC_CREAT)) == -1) { perror("semget"); exit(EXIT_FAILURE); } if(semctl(semid,0,SETVAL,0) == -1) { printf("sem init error"); if(semctl(semid,0,IPC_RMID,0) != 0) { perror("semctl"); exit(EXIT_FAILURE); } exit(EXIT_FAILURE); } key_t key1; key1 = ftok("tmp2",4); shid = shmget(key1,10*sizeof(char),0600|IPC_CREAT); if(shid == -1) { perror("shmget"); exit(EXIT_FAILURE); } sharem = shmat(shid,NULL,0); if(sharem == NULL) { perror("shmat"); exit(EXIT_FAILURE); } while(running) { if((value = semctl(semid,0,GETVAL)) == 1) { printf("read data operate\n"); sem_b.sem_op = -1; if(semop(semid,&sem_b,1) == -1) { fprintf(stderr,"semaphore_p failed\n"); exit(EXIT_FAILURE); } printf("%s\n",sharem); } if(strcmp(sharem,"end") == 0) running--; } shmdt(sharem); if(shmctl(shid,IPC_RMID,0) != 0) { perror("shctl"); exit(EXIT_FAILURE); } if(semctl(semid,IPC_RMID,0) != 0) { perror("semctl"); exit(EXIT_FAILURE); } return 0; }