标签:共享内存
进程间通信方式包括了管道,消息队列,FIFO,共享内存,而共享内存是其中效率最高的。
共享内存(一):
引入的头文件:
#include <sys/ipc.h>
#include <sys/shm.h>
1、shmget函数
该函数用来创建共享内存
int shmget(key_t key,size_t size,int shmflag);
int fork(const char *filepath);
参数解释:
key:可以指定IPC_PRIVATE,那么系统会为你创建一个key,并且返回一个id号。也可以通过ftok函数生成一个key;注意 fork函数的参数必须是一个真实存在的文件,相同路径下的相同文件fork后的值是相同的,但是如果文件删除后重新创建,则fork后的值不相同(这一点特别要注意)。对应相同的key,获得的共享内存标识符(非负整数)也是相同的。
size:共享内存的大小。如果是获得一块内存,则该值应该为0。
shmflg:权限标志,它的作用与open函数的mode参数一样,如果要想在key标识的共享内存不存在时,创建它的话,可以与IPC_CREAT做或操作。共享内存的权限标志与文件的读写权限一样,举例来说,0644,它表示允许一个进程创建的共享内存被内存创建者所拥有的进程向共享内存读取和写入数据,同时其他用户创建的进程只能读取共享内存。
调用成功时返回一个共享内存标识符(非负整数),如果调用失败返回-1。
2、shmat函数
第一次创建完共享内存时,它还不能被任何进程访问,shmat函数的作用就是用来启动对该共享内存的访问,并把共享内存连接到当前进程的地址空间。
void *shmat(int shm_id, const void *shm_addr, int shmflg);
参数解释:
shm_id:由shmget函数返回的共享内存标识。
shm_addr:指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址。
shm_flg:是一组标志位,通常为0。
调用成功时返回一个指向共享内存第一个字节的指针,如果调用失败返回-1。
3、shmdt函数
该函数用于将共享内存从当前进程中分离。注意,将共享内存分离并不是删除它,只是使该共享内存对当前进程不再可用。
int shmdt(const void *shmaddr);
参数解释:
shmaddr:是shmat函数返回的地址指针。
调用成功时返回0,失败时返回-1。
4、shmctl函数
用来控制共享内存
int shmctl(int shm_id, int command, struct shmid_ds *buf);
shm_id:是shmget函数返回的共享内存标识符。
command:是要采取的操作,它可以取下面的三个值 :
IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。
IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值
IPC_RMID:删除共享内存段
shmid_ds结构至少包括以下成员:
struct shmid_ds
{
uid_t shm_perm.uid;
uid_t shm_perm.gid;
mode_t shm_perm.mode;
};
buf:是一个结构指针,它指向共享内存模式和访问权限的结构。
共享内存(二):
引入的头文件:
#include <sys/mman.h>
1、mmap函数
mmap()用来将某个文件内容映射到内存中,对该内存区域的存取即是直接对该文件内容的读写。
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offsize);
参数解释:
start:指向欲对应的内存起始地址,通常设为NULL,代表让系统自动选定地址,对应成功后该地址会返回。
length:代表将文件中多大的部分对应到内存。
prot:代表映射区域的保护方式,有下列组合:
PROT_EXEC 映射区域可被执行;
PROT_READ 映射区域可被读取;
PROT_WRITE 映射区域可被写入;
PROT_NONE 映射区域不能存取。
flags:会影响映射区域的各种特性:
MAP_FIXED 如果参数 start 所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此旗标。
MAP_SHARED 对应射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。
MAP_PRIVATE 对应射区域的写入操作会产生一个映射文件的复制,即私人的"写入时复制" (copy on write)对此区域作的任何修改都不会写回原来的文件内容。
MAP_ANONYMOUS 建立匿名映射,此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。
MAP_DENYWRITE 只允许对应射区域的写入操作,其他对文件直接写入的操作将会被拒绝。
MAP_LOCKED 将映射区域锁定住,这表示该区域不会被置换(swap)。
在调用mmap()时必须要指定MAP_SHARED 或MAP_PRIVATE。
fd:open()返回的文件描述词,代表欲映射到内存的文件。
offset:文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小的整数倍。
若映射成功则返回映射区的内存起始地址,否则返回MAP_FAILED(-1),错误原因存于errno 中。
2、munmap函数
对已映射的内存区域取消映射。
int munmap (void *addr, size_t len);
参数解释:
addr: 内存映射首地址
len: 内存映射大小
举个例子:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
int main(){
int fd;
void *start;
struct stat sb;
fd = open("/etc/passwd", O_RDONLY); /*打开/etc/passwd */
fstat(fd, &sb); /* 取得文件大小 */
start = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if(start == MAP_FAILED) /* 判断是否映射成功 */
return;
printf("%s", start);
munmap(start, sb.st_size); /* 解除映射 */
closed(fd);
}
使用共享内存的优缺点:
优点:我们可以看到使用共享内存进行进程间的通信真的是非常方便,而且函数的接口也简单,数据的共享还使进程间的数据不用传送,而是直接访问内存,也加快了程序的效率。同时,它也不像匿名管道那样要求通信的进程有一定的父子关系。
缺点:共享内存没有提供同步的机制,这使得我们在使用共享内存进行进程间通信时,往往要借助其他的手段来进行进程间的同步工作。
标签:共享内存
原文地址:http://jeff1573.blog.51cto.com/10418369/1665060