###################################################
共享内存区
共享内存是IPC形式中最快的,因为共享内存不和内核进行数据交换。
通过fork派生的子进程不与父进程共享内存区。
共享内存区分为:
1.posix共享内存区
2.system V共享内存区
共享内存有两种形式:
1.匿名共享内存
2.有名共享内存
-----------------------------------------------------------
posix共享内存区:
gcc -lrt
-----------------------
系统调用
#include <sys/mman.h>
内存映射文件:就是硬盘中的文件或posix的共享内存区对象。
内存映射区:就是进程的地址空间,也就是内存中的内容。
void *mmap(void *addr, size_t length, int prot, intflags, int fd, off_t offset)
mmap把一个文件或posix共享内存区对象映射到调用进程的的地址空间;
成功返回该地址空间的起始地址,失败返回MAP_FAILED。
addr:内存映射区的起始地址,一般为NULL,让进程自己选择地址。
length:映射到进程地址空间的字节数。
offset:从内存映射文件的什么地方开始映射,一般是0.
fd就是内存映射文件:
1.用open打开文件
2.用shm_open打开文件
3.特殊参数=-1
prot:对内存映射区的保护,不能超过文件的打开权限。
PROT_READ:映射区可读
PROT_WRITE:映射区可写
PROT_EXEC:映射区可执行
PROT_NONE:映射区数据不可访问
flags:被映射的数据的标识,共享和私有必须指定一个。
MAP_SHARED:变动是共享的,除了修改的进程之外的其它进程也可见。
MAP_PRIVATE:变动是私有的,只有修改的进程可见。
MAP_ANONYMOUS:不用创建文件,fd=-1,offset=0,需MAP_SHARED
用mmap将硬盘文件映射到进程空间,不创建文件的两种方法:
1.用MAP_ANONYMOUS参数,fd=-1即可
2.使用/dev/zero作为文件,用open打开/dev/zero,返回fd
int munmap(void *addr, size_t length);
从进程的地址空间删除映射关系。
addr:由mmap返回的地址;
len:映射区的大小。
int mprotect(void *addr, size_t len, int prot);
更改现有内存映射区的权限,成功返回0,失败返回-1.
addr和len要和页边界对齐。
int msync(void *addr, size_t length, int flags);
如果存储映射区内容修改了,使用该函数将内容同步到内存映射文件中,成功返回0,失败返回-1.
如果映射是私有的就不修改文件。
addr和length要和页边界对齐。
flags:指定同步标识,同步和异步必须且只能指定一个。
MS_ASYNC:执行异步写
MS_SYNC:执行同步写
MS_INVALIDATE:使高速缓存的数据失效
-----------
#include<unistd.h>
#include <sys/types.h>
int ftruncate(int fd, off_t length);
用来截取内存映射文件或共享内存区的大小。
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
int fstat(int fd, struct stat *buf);
获取内存映射文件的信息。
当fd为一个共享内存区对象时,只有下列四个参数有意义:
struct stat {
mode_t st_mode;
uid_t st_uid;
gid_t st_gid;
off_t st_size; // 文件大小
};
-----------------------
库函数
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
int shm_open(const char *name, int oflag, mode_t mode);
oflag不能指定O_WRONLY参数,且mode参数必须指定。
效果和open函数差不多,返回一个描述符fd作为mmap的fd参数。
int shm_unlink(const char *name);
删除一个共享内存区对象的名字。
-----------------------------------------------------------
system v共享内存区:
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
内核维护一个共享内存结构:
struct shmid_ds {
struct ipc_permshm_perm;
size_t shm_segsz;//共享内存大小
pid_t shm_lpid;//最后一个操作的pid
pid_t shm_cpid;//创建者的pid
shmatt_t shm_nattch;
shmat_t shm_cnattch;
time_t shm_atime;
time_t shm_dtime;
time_t shm_ctime;
};
int shmget(key_t key, size_tsize, int shmflg);
创建一个新的共享内存区,或者访问一个已经存在的共享内存区。返回共享内存区标识符。
key:既可以是ftok的返回值,也可以是IPC_PRIVATE.
size:以字节为单位,指定内存区的大小,如果是已存在的共享内存区,为0.
shmflg:
shmflg: 可以用读写权限 或 其它可选权限。
属主:SHM_R SHM_A
属组:SHM_R >> 3 SHM_A >> 3
其它:SHM_R >> 6 SHM_A >> 6
IPC_CREAT:不存在就创建,存在就返回已存在的。
IPC_CREAT | IPC_EXCL:不存在就创建,存在就返回错误。
void *shmat(int shmid, constvoid *shmaddr, int shmflg);
把已经创建的共享内存区映射到调用进程的地址空间,返回起始地址。
shmaddr:一般为NULL,让系统自己选择地址。
shmflg:一般为0.
SHM_RND:如果shmaddr不为空,映射到shmaddr指定的地址向下舍入SHMLBA个值的地方,如果没有这个标识就映射到shmaddr指定的地方。
SHM_RDONLY:只读访问
int shmdt(const void *shmaddr);
断开已存在的共享内存区和进程的地址空间的映射关系。
int shmctl(int shmid, int cmd,struct shmid_ds *buf);
对共享内存区的操作。
cmd:
IPC_STAT:获取共享内存段的值
IPC_SET:设置共享内存段的值
IPC_RMID:删除共享内存段
IPC_INFO
SHM_INFO
SHM_STAT
SHM_LOCK
SHM_UNLOCK
###################################################