共享内存
共享内存是允许两个或多个进程共享同一块内存区域,因为进程可以直接读写内存,不需要任何数据的拷贝,这是一种最快的进程间通信方式。共享内存是多进程之间的通信方法 ,这种方法通常用于一个程序的多进程间通信,实际上多个程序间也可以通过共享内存来传递信息。当然,多个进程同时访问共享区就得需要一些同步机制,如信号量或互斥锁等,这些以后再记录,本文先讲最简单的共享内存使用方式。
linux共享内存操作的四个函数
shmget函数:创建一个共享内存对象并返回共享内存标识符。
shmat函数:把创建的共享内存映射到具体的进程空间去,映射后就可以在本进程使用这块地址。
shmctl函数:共享内存管理,完成对共享内存的控制。
shmdt函数:撤销映射共享内存,但是并不删除所指定的共享内存区,而只是将先前用shmat函数连接好的共享内存脱离目前的进程。
shmget 函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key,int size,int shmflg)
返回值:若成功,返回共享内存段标识符;若出错,返回-1
参数说明:
- Key:IPC_PRIVATE (为0,比较常见的一种)
- Size:共享内存区大小
- Shmflg:同 open 函数的权限位,也可以用八进制表示法
shmat函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
char *shmat(int shmid,const void *shmaddr,int shmflg)
返回值:若成功,返回被映射的段地址;若出错,返回-1
参数说明:
- shmid:要映射的共享内存区标识符
- shmaddr:将共享内存映射到指定位置(若为 0 则表示把该段共享内存映射到调用进程的地址空间)
- Shmflg
- SHM_RDONLY:共享内存只读
- 默认 0:共享内存可读写
shmctl函数
#include <sys/types.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
返回值:若成功,返回0;若出错,返回-1
参数含义:
- shmid:共享内存标识符
cmd:
- IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中
- IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内
- IPC_RMID:删除这片共享内存
buf:共享内存管理shmid_ds结构体。
以下是 shmid_ds 结构:
struct shmid_ds
{
struct ipc_perm shm_perm; /* operation permission struct */
size_t shm_segsz; /* size of segment in bytes */
pid_t shm_lpid; /* pid of last shmop() operation */
pid_t shm_cpid; /* pid of creator */
shmatt_t shm_nattch; /* number of current attaches */
time_t shm_atime; /* last-attach time */
time_t shm_dtime; /* last-detach time */
time_t shm_ctime; /* last-change time */
};
shmdt函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr)
返回值:若成功,返回0;若出错,返回-1
参数说明:
- Shmaddr:被映射的共享内存段地址
示例程序
/* share_memory.c*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/shm.h>
#define BUFF 1024
int main ()
{
int shmid;
pid_t pid;
char *shmaddr;//共享内存地址
/*创建共享内存*/
if((shmid=shmget(IPC_PRIVATE,BUFF,0666))<0)
{
perror("shmget");
exit(-1);
}
else
printf("Create shared memory,id = %d\n",shmid);
if ((pid = fork()) < 0)
{
perror("fork");
exit(-1);
}
else if (pid == 0) //子进程
{
/*映射共享内存*/
if((shmaddr=shmat(shmid,0,0))<(char *)0)
{
perror("shmat");
exit(-1);
}
else
printf("I am child,shmat shared memory success\n");
//子进程往共享内存写数据
strcpy( shmaddr, "from child process\n");
//snprintf(shmaddr, 13, "%012d", 12345);
//本函数调用并不删除所指定的共享内存区,而只是将先前用shmat函数连接(attach)好的共享内存脱离(detach)目前的进程
shmdt(shmaddr);
return 0;
}
else //父进程
{
//保证子进程已经往共享内存写入数据了
sleep(2);
/*映射共享内存*/
if((shmaddr=shmat(shmid,0,0))<(char *)0)
{
perror("shmat");
exit(-1);
}
else
printf("I am parent,shmat shared memory success\n");
//读取共享内存的数据
printf("read from share memory: %s",shmaddr);
shmdt(shmaddr);
//等待子进程退出
waitpid(pid,NULL,0);
exit(0);
}
return 0;
}
实验结果:
ubuntu:~/test/process_test$ ./share_memory
Create shared memory,id = 0
I am child,shmat shared memory success
I am parent,shmat shared memory success
read from share memory: from child process
以上程序,我们调用shmget函数创建共享内存区,然后调用fork函数创建子进程,在子进程中调用shmat映射共享内存地址,然后往共享内存区写数据。在父进程中,同样调用shmat函数映射共享内存区,然后从共享内存区读取子进程写入的数据。
共享内存的简单应用就说到这了,下次讲消息队列。