Linux进程通信总结(三) --共享内存

一)概念:

  1)Linux和所有的UNIX操作系统都允许通过共享内存在应用程序之间共享存储空间.

  2)有两类基本的API函数用于在进程间共享内存:System v和POSIX.

  3)这两类函数上使用相同的原则,核心思想就是任何要被共享的内存都必须经过显示的分配.

  4)因为所有进程共享同一块内存,共享内存在各种进程间通信方式中具有最高的效率.

  5)内核没有对访问共享内存进行同步,所以必须提供自己的同步措施,比如数据在写入之前,不允许其它进程对其进行读写.我们这里用wait来解决这个问题.

  二)POSIX共享内存API

  1)函数shm_open和shm_unlink非常类似于为普通文件所提供的open和unlink系统调用.

  2)如果要编写一个可移植的程序,那么shm_open和shm_unlink是最好的选择.

  3)shm_open:创建一个新的共享区域或者附加在已有的共享区域上.区域被其名字标识,函数返回各文件的描述符.

  4)shm_unlink:类似于unlink系统调用对文件进行操作,直到所有的进程不再引用该内存区后才对其进行释放.

  5)mmap:用于将一个文件映射到某一内存区中,其中也使用了shm_open函数返回的文件描述符.

  6)munmap:用于释放mmap所映射的内存区域.

  7)msync:同步存取一个映射区域并将高速缓存的数据回写到物理内存中,以便其他进程可以监听这些改变.

源程序1:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/wait.h>

void error_out(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}

int main (int argc, char *argv[])
{
	int r;
	const char *memname = "/mymem";
	const size_t region_size = sysconf(_SC_PAGE_SIZE);
	int fd = shm_open(memname, O_CREAT|O_TRUNC|O_RDWR, 0666);
	if (fd == -1)
		error_out("shm_open");
	r = ftruncate(fd, region_size);
	if (r != 0)
		error_out("ftruncate");
	void *ptr = mmap(0, region_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	if (ptr == MAP_FAILED)
		error_out("MMAP");
	close(fd);
	pid_t pid = fork();
	if (pid == 0)
	{
		u_long *d = (u_long *)ptr;
		*d = 0xdeadbeef;
		exit(0);
	}
	else
	{
		int status;
		waitpid(pid, &status, 0);
		printf("child wrote %#lx\n", *(u_long *)ptr);
	}
	sleep(50);
	r = munmap(ptr, region_size);
	if (r != 0)
		error_out("munmap");
	r = shm_unlink(memname);
	if (r != 0)
		error_out("shm_unlink");
	return 0;
}

编译:

  gcc -o postix-shm postix-shm.c -lrt

  ./postix-shm

  child wrote 0xdeadbeef

  等50秒后,程序退出.

  程序分析:

  1)程序执行shm_open函数创建了共享内存区域,此时会在/dev/shm/创建mymem文件.

  2)通过ftruncate函数改变shm_open创建共享内存的大小为页大小(sysconf(_SC_PAGE_SIZE)),如果不执行ftruncate函数的话,会报Bus error的错误.

  3)通过mmap函数将创建的mymem文件映射到内存.

  4)通过fork派生出子进程,而共享区域映射通过fork调用而被继承.

  5)程序通过wait系统调用来保持父进程与子进程的同步.

  6)在非父子进程也可以通过共享内存区域的方式进行通讯.

 

  Linux共享内存的实现依赖于共享内存文件系统,该文件系统通常装载在/dev/shm,在调用shm_open系统函数的时候,会在/dev/shm/目录下生成mymem文件.

  而后程序调用shm_unlink删除mymem,这里如果卸载掉/dev/shm挂载点会怎么样呢?

  查看分区信息

  df -h

  Filesystem            Size  Used Avail Use% Mounted on

  /dev/sda1              19G  973M   17G   6% /

  tmpfs                 253M     0  253M   0% /lib/init/rw

  udev                   10M   88K   10M   1% /dev

  tmpfs                 253M     0  253M   0% /dev/shm

  卸载/dev/shm

  umount /dev/shm/

  ./posix-shm &

  child wrote 0xdeadbeef

  [1] 15476

  ls -l /dev/shm/mymem

  -rw-r--r-- 1 root root 4096 2010-10-26 14:25 /dev/shm/mymem

  我们看到shm_open只是在/dev/shm下创建文件.而不管/dev/shm是否是用tmpfs类型挂载的分区.

  如果删除/dev/shm呢?

  rmdir /dev/shm

  再次执行posix-shm

  ./posix-shm &

  child wrote 0xdeadbeef

  此时程序找不到/dev/shm,而在/dev/目录下建立共享内存文件

  ls -l /dev/mymem

  -rw-r--r-- 1 root root 4096 2010-10-26 14:29 /dev/mymem

  三)System V共享内存 API

  1)System V API广泛应用于X windows系统及其扩展版本中,许多X应用程序也使用它.

  2)shmget:创建一个新的共享区域或者附加在已有的共享区域上(同shm_open).

  3)shmat:用于将一个文件映射到内存区域中(同mmap).

  4)shmdt:用于释放所映射的内存区域(同munmap)

  5)shmctl:对于多个用户,断开其对共享区域的连接(同shm_unlink)

源程序2:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
void error_out(const char *msg)
{
	perror(msg);
	exit(EXIT_FAILURE);
}
int main (int argc, char *argv[])
{
	key_t mykey = 12345678;
	const size_t region_size = sysconf(_SC_PAGE_SIZE);
	int smid = shmget(mykey, region_size, IPC_CREAT|0666);
	if(smid == -1)
		error_out("shmget");
	void *ptr;
	ptr = shmat(smid, NULL, 0);
	if (ptr == (void *) -1)
		error_out("shmat");
	pid_t pid = fork();
	if (pid == 0)
	{
		u_long *d = (u_long *)ptr;
	*d = 0xdeadbeef;
	exit(0);
	}
	else
	{
		int status;
		waitpid(pid, &status, 0);
		printf("child wrote %#lx\n", *(u_long *)ptr);
	}
	sleep(30);
	int r = shmdt(ptr);
	if (r == -1)
		error_out("shmdt");
	r = shmctl(smid, IPC_RMID, NULL);
	if (r == -1)
		error_out("shmdt");
	return 0;
}

编译gcc sysv-shm.c -o sysv-shm -lrt

  ./sysv-shm

  child wrote 0xdeadbeef

程序分析:

  1)shmget函数使用的key_t变量在功能上等价于shm_open使用的文件名,由shmget返回的smid在功能上等价于shm_open返回的文件描述符.

  2)不同于POSIX API所创建的内存区,System V API创建的内存区在任何文件系统中都是不可见的.

  3)可以用ipcs管理System V API共享内存.



 



                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值