共享内存
(1)基本概念:
共享内存使用4步:
1 创建/打开共享内存
1.1 函数名
shmget
1.2 函数原形
int shmget(key_t key,size_t size,int shmflg)
1.3 函数功能
分配一个共享内存段
1.4 所属头文件
#include <sys/ipc.h>
#include <sys/shm.h>
1.5 返回值
成功:返回共享内存标识符
失败:返回-1
1.6 参数说明
key:标识共享内存的键值:0/IPC_PRIVATE.
当key的取值为IPC_PRIVATE,则函数shmget()将创建一块新的共享内存,大小由size决定;
当key的取值为0,而参数shmflg设置为IPC_PRIVATE这个标识,则同样会创建一块新的共享内存
当key取值不为IPC_PRIVATE时,而且也不是已建立的共享内存IPC key,则视参数shmflg中是否有IPC_CREAT标志,来决定是否建立新的共享内存,并且以key值为新共享内存的IPC key。如果没有IPC_CREAT标志,则会返回错误。
当key取值为已建立的共享内存IPC key时,如果参数shmflg中包含IPC_CREAT和IPC_EXCL,则返回错误。如果只包含这两个标志中的其中之一,或者两个都不包含,则视size的大小是否小于等于这个已存在的共享内存的大小,如果小于等于,则返回这个共享内存的ID标识符;否则,返回错误。
参数shmflg也可以用来设置共享内存的存取权限,其值相当于open()函数的mode用法,执行位不用。
size:设置申请共享内存的大小
shmflg:创建的标志
2 映射共享内存
2.1 函数名
shmat
2.2 函数原形
void *shmat(int shmid,const void *shmaddr,int shmflg)
2.3 函数功能
共享内存操作
2.4 所属头文件
#include<sys/types.h>
#include<sys/shm.h>
2.5 返回值
成功:返回共享内存映射到进程中的地址
失败:返回-1
2.6 参数说明
shmid为共享内存ID标识符。
shmaddr指定映射的地址:
如果shmaddr为0,则由内核自动分配。
如果不为0,shmflg也没有指定IPC_RND旗标,则以参数shmaddr为连接地址。
如果不为0,shmflg指定了IPC_RND旗标,则将自动将参数shmflg调整为SHMLBA的整数倍。
SHMLBA的定义有两种情况,如下:
#define SHMLBA PAGE_SIZE
#define SHMLBA (4 * PAGE_SIZE)
shmflg还可以有SHM_RDONLY,表示映射的内存只可以读。
附加说明:1.在经过fork()之后,映射的地址会被继承到子进程。
2.在经过exec()之后,映射的地址连接会自动脱离。
3.程序运行结束之后,映射的地址连接也会自动脱离。
3 分离共享内存
3.1 函数名
shmdt
3.2 函数原形
int shmdt(const void * shmaddr)
3.3 函数功能
解除共享内存映射
3.4 所属头文件
#include<sys/types.h>
#include<sys/shm.h>
3.5 返回值
成功:返回0
否则:返回-1
错误原因存于errno
3.6 参数说明
shmaddr:为shmat()映射后获得的地址
4 删除共享内存
4.1 函数名
shmctl
4.2 函数原形
int shmctl(int shmid,int cmd,struct shmid_ds *buf)
4.3 函数功能
控制共享内存的操作
4.4 所属头文件
#include<sys/ipc.h>
#include<sys/shm.h>
4.5 返回值
成功:0
出错:-1,错误原因存于error中
4.6 参数说明
shmid:为共享内存的ID标识符
buf:共享内存管理结构体。
cmd:为操作的命令
buf:
IPC_STAT 把共享内存的shmid_ds结构数据复制到buf(每个共享内存中,都包含有一个shmid_ds结构,里面保存了一些关于本共享内存的信息)
IPC_SET 将参数所指的shmid_ds结构中的shm_perm.uid、shm_perm.gid和shm_perm.mode复制到共享内存的shmid_ds结构内。
IPC_RMID 删除共享内存和其包含的数据结构
SHM_LOCK 不让此共享内存置换到 swap (什么是swap,这个本人也不理解,如果有高手知道,希望不吝赐教)
SHM_UNLOCK 允许此共享内存置换到swap
SHM_LOCK和SHM_UNLOCK为Linux特有,且唯有超级用户允许使用。
shmid_ds结构定义(linux-2.6.32.2):
struct shmid_ds {
struct ipc_perm shm_perm; /* operation perms */
int shm_segsz; /* size of segment (bytes) */
__kernel_time_t shm_atime; /* last attach time */
__kernel_time_t shm_dtime; /* last detach time */
__kernel_time_t shm_ctime; /* last change time */
__kernel_ipc_pid_t shm_cpid; /* pid of creator */
__kernel_ipc_pid_t shm_lpid; /* pid of last operator */
unsigned short shm_nattch; /* no. of current attaches */
unsigned short shm_unused; /* compatibility */
void *shm_unused2; /* ditto - used by DIPC */
void *shm_unused3; /* unused */
};
shm_segsz 共享内存的大小(bytes)。
shm_atime 最后一次attach(映射)此共享内存的时间
shm_dtime 最后一次detach(解除映射)此共享内存的时间
shm_ctime 最后一次更动此共享内存的时间。
shm_cpid 建立此共享内存的进程识别码。
shm_lpid 最后一个操作此共享内存的进程识别码。
实例:
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define KEY 1234
#define SIZE 1024
int main()
{ int shmid;
char *shmaddr;
struct shmid_ds buf;
shmid = shmget(KEY, SIZE, IPC_CREAT | 0600); /*建立共享内存*/
if (fork() == 0)
{
shmaddr = (char *) shmat(shmid, 0, 0);
strcpy(shmaddr, "Hi! I am Chiled process!/n");
printf("Child: write to shared memery: /"Hi! I am Chiled process!/"/n");
shmdt(shmaddr);
return;
}
else
{
sleep(3); /*等待子进程执行完毕*/
shmctl(shmid, IPC_STAT, &buf); /*取得共享内存的状态*/
printf("shm_segsz = %d bytes/n", buf.shm_segsz);
printf("shm_cpid = %d/n", buf.shm_cpid);
printf("shm_lpid = %d/n", buf.shm_lpid);
shmaddr = (char*) shmat(shmid, 0, SHM_RDONLY);
printf("Father: %s/n", shmaddr); /*显示共享内存内容*/
shmdt(shmaddr);
shmctl(shmid, IPC_RMID, NULL); /*删除共享内存*/
}
}