- 论坛徽章:
- 0
|
共享内存区的介绍
共享内存区是最快的可用IPC形式,一旦这样的内存区映射到共享它的进程的地址空间,这些进程间数据的传递就不再通过执行任何进入内核的系统调用来传递彼此的数据,节省了时间。
共享内存和消息队列,FIFO,管道传递消息的区别:
后者,消息队列,FIFO,管道的消息传递方式一般为
1:服务器得到输入
2:通过管道,消息队列写入数据,通常需要从进程拷贝到内核。
3:客户从内核拷贝到进程
4:然后再从进程中拷贝到输出文件
上述过程通常要经过4次拷贝,才能完成文件的传递。
而共享内存只需要
1:从输入文件到共享内存区
2:从共享内存区输出到文件
上述过程不涉及到内核的拷贝,所以花的时间较少。
首先,我们从fork程序引入今天的话题,fork函数最难理解的就是fork程序执行一次,但是却返回两次,返回值为父进程和子进程的进程id,父进程返回父进程的id,而子进程返回的进程id为0,子进程只是在父进程中的返回进程id为0,但是不是子进程的进程id为零,这一点要明确。子进程共享父进程的代码段,而数据段,堆栈段这复制到到新的子进程,对子进程的堆栈和数据进行修改并不影响父进程的代码。如果要深入去理解,其实子进程也和父进程共享堆栈段和数据段,只是把修改过的数值进行了保存,无疑,优化了操作系统的性能。下面程序可以在linux下面编译,让大家对fork有一个初步的认识。
//qbforkeg.c
#include
#include
int main(void)
{
int N=400;
int count =0;
setbuf(stdout,NULL);
if(fork()==0)
{
while(N>0)
printf("child The value of N = :%d,count = %d\n",N--,count++);
return 0;
}
while(N>0)
printf("parent The value of N = :%d,count = %d\n",N--,count++);
return 0;
}//end
:cc qbforkeg.c -o qbforkeg
:./qbforkeg
上述setbuf把我的程序设置成为非缓冲模式,可以避免输出不恰当的交叉。从代码的输出可以看出,父进程和子进程的N并不是一样的,而是不同的两个值,说明,父进程和子进程并不共享数据段。
下面这段程序,使用共享内存的方法:
//源代码shm.c
#include
#include
#include
#include
#include
#include
int main(void)
{
int fd, zero = 0;
sem_t *mutex;
int *ptr;
fd = open("/dev/zero", O_RDWR|O_CREAT, 0666);
ptr = mmap(NULL,sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, fd,0);
close(fd);
mutex = sem_open("shm", O_CREAT|O_EXCL, 0666, 1);
sem_unlink("shm");
setbuf(stdout, NULL);
if(fork() == 0)
{
while((*ptr)
}
system("rm /tmp/test");
return 0;
}//END
:cc shm.c -o shm
:./shm
可以得到结果
上述过程解释如下:
1:打开SVR4提供/dev/zero的设备文件,然后在mmap中调研那个该描述字,该设备读时返回的字节全为0,写往该设备的任何字节被丢弃。
2:调用mmap把刚才打开的文件映射到本进程的内存空间。第一个参数为NULL,有系统来选择它在进程中的起始地址。长度参数十亿个整数的大小,保护模式参数制定读写访问,通过把第四个参数制定为MAP_SHARED,父进程把所做的任何变动子进程都能看到,函数返回值是待共享内存区的起始地址,我们把它保存在ptr中。
3:之后创建并初始化一个信号灯,它保护一个共享变量的对象,然后删除了该信号灯的名字,但是尽管删除了他的路径,对于已经打开的信号灯却没有影响。这样,这样如果本程序夭折,该路径名也从系统中删除。
上述程序得到的结果显示,在共享内存的情况下,*ptr被两个进程共享。
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/83146/showart_1354888.html |
|