1.概述
System V共享内存区在概念上类似与Posix共享内存区。代之以调用shm_open后调用mmap,先调用shmget,在调用shmat,在终端市使用ipcs
命令可以查看SystemV的IPC对象。
2.SystemV 共享内存编程
2.1shmget函数
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
第一个参数 key 通过 ftok 获取。
第二个参数 size 以字节为单位指定内存区大小。
第三个参数 shmflg 表示权限组合 可以是 IPC_EXCL | IPC_CREAT | 0600
调用成功后,该共享内存区会被以size的大小初始化为0,并返回一个shmid让我们操作该共享内存区。
2.2shmat函数
该函数可以将打开的共享内存区后,将其附接到调用进程的地址空间。
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
第一个参数 shmid 由 shmget返回
第二个参数 shmaddr是一个非空指针返回值取决于shmflg(如果指定NULL,则由系统选择)
第三个参数 shmflg如果指定了SHM_RND,则相应的共享内存区附接到由shmaddr参数指定的地址。
否则,共享内存区将附接到shmaddr参数指定的地址向下舍入SHMLBA常值。
2.3shmdt函数
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
调用这个函数进程可以主动切断这个内存区,不过如果没有调用该函数,当进程结束时会自动切断。切断连接后,共享内存区依然存在。
2.4shctl函数
该函数完成对共享内存区的各种操作。
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
//其中
struct shmid_ds {
struct ipc_perm shm_perm; /* Ownership and permissions */
size_t shm_segsz; /* Size of segment (bytes) */
time_t shm_atime; /* Last attach time */
time_t shm_dtime; /* Last detach time */
time_t shm_ctime; /* Last change time */
pid_t shm_cpid; /* PID of creator */
pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */
shmatt_t shm_nattch; /* No. of current attaches */
...
};
The ipc_perm structure is defined as follows (the highlighted fields are settable using IPC_SET):
struct ipc_perm {
key_t __key; /* Key supplied to shmget(2) */
uid_t uid; /* Effective UID of owner */
gid_t gid; /* Effective GID of owner */
uid_t cuid; /* Effective UID of creator */
gid_t cgid; /* Effective GID of creator */
unsigned short mode; /* Permissions + SHM_DEST and
SHM_LOCKED flags */
unsigned short __seq; /* Sequence number */
};
该函数有三个命令:
IPC_RMID:删除
IPC_SET:设置
IPC_STAT:获取
3.共享内存区的限制
系统默认的内容,可通过下述命令查看:
cat /proc/sys/kernel/shmmax //共享内存区最大字节数
cat /proc/sys/kernel/shmall //最多共享内存区数
cat /proc/sys/kernel/shmmni //最大共享内存区标识符数
4.systemV共享内存区读写程序示例
头文件
//shm.h
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#include <time.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
#include <sys/ipc.h>
#include <sys/shm.h>
写端
//shmwrite.c
#include "shm.h"
#define PATHNAME "."
int
main(int argc, char **argv)
{
int id;
int flag;
char *ptr;
size_t length=1024;
key_t key;
struct shmid_ds buff;
key = ftok(PATHNAME,1);
if(key<0)
{
printf("ftok error\r\n");
return -1;
}
id = shmget(key, length,IPC_CREAT | IPC_EXCL| S_IRUSR | S_IWUSR );
if(id<0)
{
printf("errno: %s\r\n",strerror(errno));
printf("shmget error\r\n");
return -1;
}
ptr = shmat(id, NULL, 0);
if(ptr==NULL)
{
printf("shmat error\r\n");
return -1;
}
shmctl(id,IPC_STAT,&buff);
int i;
for(i=0;i<buff.shm_segsz;i++)
{
*ptr++ = i%256;
}
return 0;
}
读端
#include "shm.h"
int
main(int argc, char **argv)
{
const char * const pathname=".";
int id;
int flag;
char *ptr;
size_t length=1024;
key_t key;
struct shmid_ds buff;
key = ftok(pathname,1);
if(key<0)
{
printf("ftok error\r\n");
return -1;
}
flag = IPC_CREAT | 0400;
id = shmget(key, length, flag);
if(id<0)
{
printf("shmget error\r\n");
return -1;
}
ptr = shmat(id, NULL, 0);
if(ptr==NULL)
{
printf("shmat error\r\n");
return -1;
}
shmctl(id,IPC_STAT,&buff);
int i;
unsigned char c;
for(i=0;i<buff.shm_segsz;i++)
{
c=*ptr++;
printf("ptr[%d]=%d\r\n",i,c);
}
shmctl(id, IPC_RMID, NULL);
return 0;
}
Makefile
PROGS =Read Write
CLEANFILES = core core.* *.core *.o temp.* *.out typescript* \
*.lc *.lh *.bsdi *.sparc *.uw
all :${PROGS}
CFLAGS+=-g
LIBS+=-lpthread -lrt
Read: shmread.o
${CC} ${CFLAGS} ${LIBPATH} $^ -o $@ ${LIBS}
@rm *.o
Write: shmwrite.o
${CC} ${CFLAGS} ${LIBPATH} $^ -o $@ ${LIBS}
@rm *.o
clean:
rm -f ${PROGS} ${CLEANFILES}
运行效果图: