ipc 共享内存 shared memmory

来源:互联网 发布:gfa交易算法gfajiaoyi 编辑:程序博客网 时间:2024/05/20 03:08

下面两篇博客对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 1024int 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分别对进程通信进行创建删除显示信息等操作




0 0