《UNIX网络编程 卷2》 笔记: Posix共享内存区

Posix.1提供了两种在无亲缘关系进程间共享内存区的方法:

    1. 内存映射文件。用open打开一个文件,然后调用mmap将它映射到当前进程的地址空间。

    2. 共享内存区对象。用shm_open打开一个Posix共享内存区对象,然后调用mmap将它映射到当前进程的地址空间。

Posix 把两者合称为内存区对象。上节我们讲述的父子进程间共享一个全局变量的例子使用的就是第一种方法,本节我们讲述第二种方法。

Linux提供的Posix共享内存区对象API如下:

#include 
#include         /* For mode constants */
#include            /* For O_* constants */

/*创建或打开一个共享内存区对象*/
int shm_open(const char *name, int oflag, mode_t mode);
/*删除一个共享内存区对象*/
int shm_unlink(const char *name);
ftruncate函数可用来指定新创建的共享内存区对象大小或修改已存在的共享内存区对象大小。

#include 
#include 

int ftruncate(int fd, off_t length);
fstat函数可用来获取共享内存区对象信息。

#include 
#include 
#include 

int fstat(int fd, struct stat *buf);

下面我们将给出一个使用Posix共享内存区在多个进程间共享数据的例子。在这个例子中,多个进程间共享一个32位的计数器,每个进程都对这个计数器进行持续加1操作。

我们先写一个名为“server1”的程序创建一个共享内存区对象和一个用于进程间同步的有名信号量。代码如下:

#include "unpipc.h"

struct shmstruct{
	int count; /*计数器*/
};

sem_t *mutex;

int main(int argc, char **argv)
{
	int fd;

	if (argc != 3)
		err_quit("usage: server1  ");
	
	shm_unlink(argv[1]);
	/*创建内存共享区对象*/
	fd = Shm_open(argv[1], O_RDWR | O_CREAT | O_EXCL, FILE_MODE);
	/*设置共享内存区对象大小*/
	Ftruncate(fd, sizeof(struct shmstruct));
	Close(fd);

	sem_unlink(argv[2]);
	/*创建信号量*/
	mutex = Sem_open(argv[2], O_CREAT | O_EXCL, FILE_MODE, 1);
	Sem_close(mutex);

	exit(0);
}

执行如下命令创建一个名为“123”的共享内存区对象和一个名为“123”信号量:

./server1 /123 /123

然后写一个名为“client1”的程序使用已创建的共享内存区对象和信号量,对共享内存区内的计数器进行持续加1操作。代码如下:

#include "unpipc.h"

/*共享的数据结构*/
struct shmstruct{
	int count;  /*计数器*/
};

sem_t *mutex;

int main(int argc, char **argv)
{
	int fd, i, nloop;
	pid_t pid;
	struct shmstruct *ptr;

	if (argc != 4)
		err_quit("usage: client1   <#loops>");
	nloop = atoi(argv[3]);

	/*打开共享内存区对象*/
	fd = Shm_open(argv[1], O_RDWR, FILE_MODE);
	/*映射共享内存区对象*/
	ptr = Mmap(NULL, sizeof(struct shmstruct), PROT_READ | PROT_WRITE, 
				MAP_SHARED, fd, 0);
	Close(fd);

	/*打开信号量*/
	mutex = Sem_open(argv[2], 0);

	pid = getpid();
	/*给共享内存区计数器持续加1*/
	for (i = 0; i < nloop; i++) {
		Sem_wait(mutex);
		printf("pid %ld: %d\n", (long)pid, ptr->count++);
		Sem_post(mutex);
	}

	exit(0);

}
然后我们执行如下的命令几乎同时启动两个client1进程,每个进程为共享的计数器增加10次计数:

./client1 /123 /123 10 &  ./client1 /123 /123 10 &

其中一次运行结果如下:

liu@ubuntu:~/work$ pid 120684: 0
pid 120684: 1
pid 120684: 2
pid 120684: 3
pid 120684: 4
pid 120684: 5
pid 120684: 6
pid 120684: 7
pid 120684: 8
pid 120684: 9
pid 120683: 10
pid 120683: 11
pid 120683: 12
pid 120683: 13
pid 120683: 14
pid 120683: 15
pid 120683: 16
pid 120683: 17
pid 120683: 18
pid 120683: 19

可以看到,该计数器被两个无亲缘关系的进程共享。


你可能感兴趣的:(UNIX网络编程,卷2)