Linux进程间通信——共享内存

2019-07-12 14:14发布

一、共享内存概述         共享内存是一种最为高效的进程间通信方式。内核为进程提供一块内存区,每个进程可以将其映射到自己的私有空间,并且可以直接对内存进行读写,因此进程不需要对数据进行复制。当一个进程对数据进行修改时,其他进程可以立即响应。但是由于共享内存的共享性质,因此需要互斥锁和信号量机制来进行同步。 二、共享内存的应用 1.函数说明         共享内存的实现可分为三步: (1) 通过shmget()创建共享内存,从内存中获得一段共享内存区域 (2) 通过shmat()映射共享内存,把共享内存映射到具体的进程中 (3) 通过shmdt()撤销映射操作 2.函数格式 shmget()函数语法要点 所需头文件 #include #include #include 函数原型 int shmget(key_t key,int size,int shmflg) 函数传入值 key:共享内存的键值,多个进程可以通过它访问同一个共享内存,其中有个特殊值IPC_PRIVATE。它用于创建当前进程的私有共享内存 size:共享内存大小 shmflg:同open()函数的权限值,也可以用八进制表示 函数返回值 成功:共享内存段标识符 出错:-1 shmat()函数语法要点 所需头文件 #include #include #include 函数原型 char *shmat(int shmid,const void *shmaddr,int shmflg) 函数传入值 shmid:要映射的共享内存区域标识符 shmaddr:将共享内存映射到指定地址(若为0则表示系统自动分配地址并把该段共享内存映射到进程的地址空间) shmflg: SHM_RDONLY:共享内存只读 默认0:共享内存可读写 函数返回值 成功:被映射的段地址 出错:-1 shmdt()函数语法要点 所需头文件 #include #include #include 函数原型 int shmdt(const void *shmaddr) 函数传入值 shmaddr:被映射的共享内存段地址 函数返回值 成功:0 出错:-1 (3)使用实例 /* shmem.c */ #include #include #include #include #include #include #define BUFSIZE 2048 int main(void) { pid_t pid; int shmid; char *shm_addr; char flag[] = "WROTE"; char buff[BUFSIZE]; //注意这里不能使用char *buff if((shmid = shmget(IPC_PRIVATE,BUFSIZE,0666)) < 0) { printf("shmget error. "); exit(1); } printf("Create shared-menory: %d ",shmid); system("ipcs -m"); pid = fork(); if(pid == -1) { printf("fork error. "); exit(1); } else if(pid == 0) { if((shm_addr = shmat(shmid,0,0)) == (void*)-1) { printf("Child shmat error. "); exit(1); } printf("Child: Deattach shared-memory "); system("ipcs -m"); if((shmctl(shmid,IPC_RMID,NULL)) == -1) { printf("Child shmctl(IPC_RMID) error "); exit(1); } printf("Child:Delete shared-memory. "); system("ipcs -m"); } else { if((shm_addr = shmat(shmid,0,0)) == (void*)-1) { printf("Parent shmat error. "); exit(1); } printf("Parent: Attach shared-memory: %p ",shm_addr); sleep(1); printf("Input some string: "); fgets(buff,BUFSIZE,stdin); strncpy(shm_addr+strlen(flag),buff,strlen(buff)); strncpy(shm_addr,flag,strlen(flag)); if((shmdt(shm_addr)) < 0) { printf("Parent shmdt error. "); exit(1); } printf("Parent: Deattach shared-memory. "); system("ipcs -m"); waitpid(pid,NULL,0); printf("Finished. "); exit(0); } } 三、信号量实现通信内存同步 实例 makefile /* makefile */ all : shm_producer shm_customer .PHONY : all OBJS1 = shm_producer.o sem_com.o OBJS2 = shm_customer.o sem_com.o CC = gcc CFLAGS = -Wall -O -g shm_producer:$(OBJS1) $(CC) -o shm_producer $(OBJS1) $(CFLAGS) shm_customer:$(OBJS2) $(CC) -o shm_customer $(OBJS2) $(CFLAGS) $(OBJS1):%.o:%.c $(CC) -c $< -o $@ $(OBJS2):%.o:%.c $(CC) -c $< -o $@ .PHONY : clean clean: -$(RM) shm_producer shm_customer $(OBJS1) $(OBJS2) sem_com.h /* sem_com.h */ #ifndef _SEM_COM_H_ #define _SEM_COM_H_ union semun { int val; struct semid_ds *buf; unsigned short *array; }; int sem_init(int sem_id,int init_value); int sem_del(int sem_id); int sem_p(int sem_id); int sem_v(int sem_id); #endif sem_com.c /* sem_com.c*/ #include #include #include #include #include #include #include #include #include #include "sem_com.h" int sem_init(int sem_id,int init_value) { union semun sem_union; sem_union.val = init_value; if(semctl(sem_id,0,SETVAL,sem_union) == -1) { perror("Initialize semaphore"); return -1; } return 0; } int sem_del(int sem_id) { union semun sem_union; if(semctl(sem_id,0,IPC_RMID,sem_union) == -1) { perror("Delete semaphore"); return -1; } return 0; } int sem_p(int sem_id) { struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = -1; sem_b.sem_flg = SEM_UNDO; if(semop(sem_id,&sem_b,1) == -1) { perror("P operations"); return -1; } return 0; } int sem_v(int sem_id) { struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1; sem_b.sem_flg = SEM_UNDO; if(semop(sem_id,&sem_b,1) == -1) { perror("V operations"); return -1; } return 0; } shm_com.h /* shm_com.h */ #include #include #include #include #include #include #include #include #define SHM_BUFSIZE 2048 struct shm_buff { int pid; char buf[SHM_BUFSIZE]; }; shm_producer.c /* shm_producer.c */ #include "sem_com.h" #include "shm_com.h" int ignore_signal(void) { signal(SIGINT,SIG_IGN); signal(SIGQUIT,SIG_IGN); signal(SIGSTOP,SIG_IGN); return 0; } int main() { int semid,shmid; void *shm_addr = NULL; struct shm_buff *shm_buff_addr; char buf[SHM_BUFSIZE]; ignore_signal(); semid = semget((key_t)1234,1,IPC_CREAT|0666); if(semid == -1) { printf("Producer:semget error. "); exit(1); } sem_init(semid,1); shmid = shmget((key_t)2345,SHM_BUFSIZE,IPC_CREAT|0666); if(shmid == -1) { printf("Producer:shmget error. "); sem_del(semid); exit(1); } if((shm_addr = shmat(shmid,0,0)) == (void *)-1) { printf("Producer:shmat error. "); sem_del(semid); exit(1); } printf("Producer:Attach shm:%p ",shm_addr); shm_buff_addr = (struct shm_buff *)shm_addr; do { sem_p(semid); printf("Enter('quit' to exit):"); if(fgets(shm_buff_addr->buf,SHM_BUFSIZE,stdin) == NULL) { printf("Producer:fgets error. "); sem_v(semid); break; } shm_buff_addr->pid = getpid(); sem_v(semid); }while(strncmp(shm_buff_addr->buf,"quit",4)); sem_del(semid); if(shmdt(shm_addr) == -1) { printf("Producer: shmdt error. "); exit(1); } exit(0); } shm_customer.c /* shm_customer.c */ #include "sem_com.h" #include "shm_com.h" int main() { int semid,shmid; struct shm_buff *shm_buff_addr; char buf[SHM_BUFSIZE]; char *shm_addr; semid = semget((key_t)1234,1,0666); if(semid == -1) { printf("Customer: semget error. "); exit(1); } shmid = shmget((key_t)2345,SHM_BUFSIZE,0666); if(shmid == -1) { printf("Customer: shmget error. "); exit(1); } if((shm_addr = shmat(shmid,(void *)0,0)) == (void *)-1) { printf("Customer: shmat error. "); exit(1); } printf("Customer: Attach shm: %p ",shm_addr); shm_buff_addr = (struct shm_buff *)shm_addr; while(1) { sem_p(semid); printf("Customer:Producer PID:%d :%s ",shm_buff_addr->pid,shm_buff_addr->buf); if(strncmp(shm_buff_addr->buf,"quit",4) == 0) break; shm_buff_addr->pid = 0; memset(shm_buff_addr->buf,0,SHM_BUFSIZE); sem_v(semid); } if((shmdt(shm_buff_addr)) == -1) { printf("Customer:shmdt error. "); exit(1); } if((shmctl(shmid,IPC_RMID,NULL)) == -1) { printf("Customer:shmctl(IPC_RMID) error. "); exit(1); } exit(0); }