您的位置:首页 > 其它

ipc 共享内存 shared memmory

2014-11-01 14:06 267 查看
下面两篇博客对ipc shares memory 讲述的比较清晰

1.http://blog.chinaunix.net/uid-26833883-id-3230564.html

2.http://blog.csdn.net/ljianhui/article/details/10253345

共享内存(shared memory)是最简单的Linux进程间通信方式之一。使用共享内存,不同进程可以对同一块内存进行读写。由于所有进程对共享内存的访问就和访问自己的内存空间一样,而不需要进行额外系统调用或内核操作,同时还避免了多余的内存拷贝,所以,这种方式是效率最高、速度最快的进程间通信方式。

这种最大限度的自由也给共享内存带来了缺点:内核并不提供任何对共享内存访问的同步机制,比如同时对共享内存的相同地址进行写操作,则后写的数据会覆盖之前的数据。所以,使用共享内存一般还需要使用其他IPC机制(如信号量)进行读写同步与互斥。

基本原理

了解Linux内存管理机制,就很容易知道共享内存的原理了。大家知道,内核对内存的管理是以页(page)为单位的,Linux下一般一个page大小是4k。而程序本身的虚拟地址空间是线性的,所以内核管理了进程从虚拟地址空间到起对应的页的映射。创建共享内存空间后,内核将不同进程虚拟地址的映射到同一个页面:所以在不同进程中,对共享内存所在的内存地址的访问最终都被映射到同一页面。下图演示了共享内存的工作机制:



代码如下:

#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/stat.h>

#define BUFF_SIZE 1024

int father_do_work(int shmid)
{
char *buf;
void *shmaddr;
sem_t *prsem;
sem_t *pwsem;

//有名信号量
if((prsem = sem_open("rsem",O_CREAT,0666,0)) == SEM_FAILED)
{
perror("Fail to sem open");
return -1;
}

//有名信号量
if((pwsem = sem_open("wsem",O_CREAT,0666,1)) == SEM_FAILED)
{
perror("Fail to sem open");
return -1;
}

//映射共享内存
if((shmaddr = shmat(shmid,NULL,0)) == (void *)-1)
{
perror("Fail to shmat");
exit(EXIT_FAILURE);
}

buf = (char *)shmaddr;

while(1)
{
if(sem_wait(pwsem) < 0)
{
perror("Fail to sem wait");
break;
}

printf(">");
fgets(buf,BUFF_SIZE,stdin);
buf[strlen(buf) - 1] = '\0';

if(sem_post(prsem) < 0)
{
perror("Fail to sem post");
break;
}

if(strncmp(buf,"quit",4) == 0)
{
if(shmdt(shmaddr) < 0)
{
perror("Fail to shmaddr");
exit(EXIT_FAILURE);
}

break;
}

usleep(500);
}

return 0;
}

int child_do_work(int shmid)
{
char *buf;
void *shmaddr;
sem_t *prsem;
sem_t *pwsem;

//
if((prsem = sem_open("rsem",O_CREAT,0666,0)) == SEM_FAILED)
{
perror("Fail to sem open");
return -1;
}

if((pwsem = sem_open("wsem",O_CREAT,0666,1)) == SEM_FAILED)
{
perror("Fail to sem open");
return -1;
}

//映射共享内存
if((shmaddr = shmat(shmid,NULL,0)) == (void *)-1)
{
perror("Fail to shmat");
exit(EXIT_FAILURE);
}

buf = (char *)shmaddr;

while(1)
{
if(sem_wait(prsem) < 0)
{
perror("Fail to prsem");
break;
}

printf("read buf : %s.\n",buf);

if(sem_post(pwsem) < 0)
{
perror("Fail to pwsem");
break;
}

if(strncmp(buf,"quit",4) == 0)
{
if(shmdt(shmaddr) < 0)
{
perror("Fail to shmaddr");
exit(EXIT_FAILURE);
}

break;
}
}

return 0;
}

int main()
{
int shmid;
int pid;
void *shmaddr;

//创建共享内存
if((shmid = shmget((key_t)16,BUFF_SIZE,0666 | IPC_CREAT)) < 0)
{
perror("Fail to shmget");
exit(EXIT_FAILURE);
}

if((pid = fork()) < 0)
{

perror("Fail to fork");
exit(EXIT_FAILURE);

}else if(pid == 0){

child_do_work(shmid);

}else{

father_do_work(shmid);
wait(NULL);

if(shmctl(shmid,IPC_RMID,NULL) < 0)
{
perror("Fail to shmctl");
exit(EXIT_FAILURE);
}
}

exit(EXIT_SUCCESS);
}


同时linux shell通过命令ipcs ipcrm分别对进程通信进行创建删除显示信息等操作

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: