一、共享内存概述
共享内存是一种最为高效的进程间通信方式。内核为进程提供一块内存区,每个进程可以将其映射到自己的私有空间,并且可以直接对内存进行读写,因此进程不需要对数据进行复制。当一个进程对数据进行修改时,其他进程可以立即响应。但是由于共享内存的共享性质,因此需要互斥锁和信号量机制来进行同步。
二、共享内存的应用
1.函数说明
共享内存的实现可分为三步:
(1) 通过shmget()创建共享内存,从内存中获得一段共享内存区域 |
(2) 通过shmat()映射共享内存,把共享内存映射到具体的进程中 |
(3) 通过shmdt()撤销映射操作 |
2.函数格式
所需头文件 | #include #include #include |
---|---|
函数原型 | int shmget(key_t key,int size,int shmflg) |
函数传入值 | key:共享内存的键值,多个进程可以通过它访问同一个共享内存,其中有个特殊值IPC_PRIVATE。它用于创建当前进程的私有共享内存 |
size:共享内存大小 | |
shmflg:同open()函数的权限值,也可以用八进制表示 | |
函数返回值 | 成功:共享内存段标识符 |
出错:-1 |
所需头文件 | #include #include #include |
|
---|---|---|
函数原型 | char *shmat(int shmid,const void *shmaddr,int shmflg) | |
函数传入值 | shmid:要映射的共享内存区域标识符 | |
shmaddr:将共享内存映射到指定地址(若为0则表示系统自动分配地址并把该段共享内存映射到进程的地址空间) | ||
shmflg: | SHM_RDONLY:共享内存只读 | |
默认0:共享内存可读写 | ||
函数返回值 | 成功:被映射的段地址 | |
出错:-1 |
所需头文件 | #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.\n");
exit(1);
}
printf("Create shared-menory: %d\n",shmid);
system("ipcs -m");
pid = fork();
if(pid == -1)
{
printf("fork error.\n");
exit(1);
}
else if(pid == 0)
{
if((shm_addr = shmat(shmid,0,0)) == (void*)-1)
{
printf("Child shmat error.\n");
exit(1);
}
printf("Child: Deattach shared-memory\n");
system("ipcs -m");
if((shmctl(shmid,IPC_RMID,NULL)) == -1)
{
printf("Child shmctl(IPC_RMID) error\n");
exit(1);
}
printf("Child:Delete shared-memory.\n");
system("ipcs -m");
}
else
{
if((shm_addr = shmat(shmid,0,0)) == (void*)-1)
{
printf("Parent shmat error.\n");
exit(1);
}
printf("Parent: Attach shared-memory: %p\n",shm_addr);
sleep(1);
printf("Input some string:\n");
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.\n");
exit(1);
}
printf("Parent: Deattach shared-memory.\n");
system("ipcs -m");
waitpid(pid,NULL,0);
printf("Finished.\n");
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.\n");
exit(1);
}
sem_init(semid,1);
shmid = shmget((key_t)2345,SHM_BUFSIZE,IPC_CREAT|0666);
if(shmid == -1)
{
printf("Producer:shmget error.\n");
sem_del(semid);
exit(1);
}
if((shm_addr = shmat(shmid,0,0)) == (void *)-1)
{
printf("Producer:shmat error.\n");
sem_del(semid);
exit(1);
}
printf("Producer:Attach shm:%p\n",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.\n");
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.\n");
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.\n");
exit(1);
}
shmid = shmget((key_t)2345,SHM_BUFSIZE,0666);
if(shmid == -1)
{
printf("Customer: shmget error.\n");
exit(1);
}
if((shm_addr = shmat(shmid,(void *)0,0)) == (void *)-1)
{
printf("Customer: shmat error.\n");
exit(1);
}
printf("Customer: Attach shm: %p\n",shm_addr);
shm_buff_addr = (struct shm_buff *)shm_addr;
while(1)
{
sem_p(semid);
printf("Customer:Producer PID:%d :%s\n",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.\n");
exit(1);
}
if((shmctl(shmid,IPC_RMID,NULL)) == -1)
{
printf("Customer:shmctl(IPC_RMID) error.\n");
exit(1);
}
exit(0);
}