ipc 共享内存 shared memmory

2 篇文章 0 订阅

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




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值