首页 > 代码库 > Linux环境编程之共享内存区(二):Posix共享内存区

Linux环境编程之共享内存区(二):Posix共享内存区

现在将共享内存区的概念扩展到将无亲缘关系进程间共享的内存区包括在内。Posix提供了两种在无亲缘关系进程间共享内存区的方法

1、内存映射文件:由open函数打开,由mmap函数把得到的描述符映射到当前进程地址空间中的一个文件。(上一节就是这种技术)

2、共享内存区对象:由shm_open打开一个Posix名字(也许是在文件系统中的一个路径名),所返回的描述符由mmap函数映射到当前进程的地址空间。(本节内容)

Posix共享内存区涉及以下两个步骤要求:

1、指定一个名字参数调用shm_open,以创建一个新的共享内存区对象或打开一个已存在的共享内存区对象。

2、调用mmap把这个共享内存区映射到调用进程的地址空间。

传递给shm_open的名字参数随后由希望共享内存区的任何其他进程使用。

#include <sys/mman.h>
int	shm_open(const char *name, int oflags, mode_t mode);		// 返回值:成功返回非负描述符,出错则为-1
int	shm_unlink(const char *name);							//返回值:成功返回0,出错返回-1

oflag参数必须活着含有O_RDONLY(只读)标志,或者含有O_RDWR(读写)标志,还可以指定如下标志:O_CREAT、O_EXCL或O_TRUNC。

mode参数指定权限位,它在指定了O_CREAT标志的前提下使用。注意:与mq_open和sem_open函数不同,shm_open的mode参数总是必须指定。如果没有指定O_CREAT标志,那么读参数可以指定为0。

shm_open的返回值是一个整数描述符。shm_unlink函数删除一个共享内存区对象的名字。跟所有其他unlink函数一样,删除一个名字不会影响对于其底层支撑对象的现有引用,直到对于该对象的引用全部关闭为止。


处理mmap的时候,普通文件或共享内存区对象的大小可以通过调用ftruncate修改。

#include <unistd.h>
int	ftruncate(int fd, off_t	length);

Posix就该函数对普通文件和共享内存区对象的处理定义有如下不同:

1、普通文件:如果该文件的大小大于length参数,额外的数据就被丢弃掉。如果该文件的大小小于length,那么该文件是否修改以及其大小是否增长是未加说明的。

2、共享内存区对象:ftruncate把该对象的大小设置成length字节。

我们调用ftruncate来指定新创建的共享内存区对象的大小,或者修改已存在的对象的大小。当打开一个已存在的共享内存区对象时,可调用fstat来获取有关该对象的信息。

#include <sys/types.h>
#include <sys/stat.h>
int	fstat(int fd, struct stat *buf);  //成功返回0,出错返回-1
示例程序如下:

shmcreate程序:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>

#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)

int
main(int argc, char **argv)
{
	int 	c, fd, flags;
	char 	*ptr;
	off_t	length;

	flags = O_RDWR | O_CREAT;
	while((c = getopt(argc, argv, "e")) != -1){
		switch(c){
			case 'e';
				flags |= O_EXCL;
				break;	
		}
	}
	if(optind != argc -2){
		printf("usage:shmcreate [-e] <name> <length>\n");
		return -1;
	}
	length = atoi(argv[optind] + 1);

	fd = shm_open(argv[optind], flags, FILE_MODE);
	ftruncate(fd, length);

	ptr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

	exit(0);
}
shmunlink程序

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>

int
main(int argc, char **argv)
{
	if(argc != 2){
		printf("usage:shunlink <name>\n");	
		return -1;
	}

	shm_unlink(argv[1]);

	exit(0);
}
shmwrite程序

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>

#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)

int
main(int argc, char **argv)
{
	int 	i, fd;
	struct	stat stat;
	unsigned char *ptr;

	if(argc != 2){
		printf("usage:shwrite <name>\n");	
		return -1;
	}

	/*open, get size, map*/
	fd = shm_open(argv[1], O_RDWR, FILE_MODE);
	fstat(fd, &stat);
	ptr = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE);
	close(fd);

	/*set : ptr[0] = 0, ptr[1] = 1, etc.*/
	for(i = 0; i < stat.st_size; i++)
		*ptr++ = i % 256;

	exit(0);
}
shmread程序

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>

#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)

int
main(int argc, char **argv)
{
	int 	i, fd;
	struct stat stat;
	unsigned char c, *ptr;

	if(argc != 2){
		printf("usage:shmread <name>\n");	
		return -1;
	}

	/*open, get size, map*/
	fd = shm_open(argv[1], O_RDONLY, FILE_MODE);
	fstat(fd, &stat);
	ptr = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
	close(fd);

	/*check that ptr[0] = 0, ptr[1] = 1, etc*/
	for(i = 0; i < stat.st_size; i++){
		if((c = *ptr++) != (i % 256))	
			printf("ptr[%d] = %d", i, c);
	}
	exit(0);
}