进程间通信之共享内存shared memory

共享内存是一种简单而高效的进程间通信方法。管道,消息队列等通信方法需要在主存和用户空间之间进行4次数据复制,而共享内存只需要2次。分析如下:
管道,消息队列等:
第一次:数据产生后需要写入进程A的用户空间
第二次:把数据从进程A的用户空间复制到内核空间中
第三次:把数据从内核空间复制到进程B的用户空间中
第四次:把数据从进程B的用户空间写入输出文件
共享内存的实现是将内核空间的物理内存映射到不同进程的虚拟地址,这样不同进程通过各自的虚拟地址就可以直接访问相同的物理内存,从而实现数据的共享。
但是进程A在写用户空间时,直接修改的就是物理内存,进程B即时的就能看见修改,
所以共享内存需要配合其他进程同步机制一起使用。
下面就一个实际例子来说明写入共享内存可以即时的被其他进程看到,也说明下访问共享内存时加入同步机制的必要性。
reader进程创建一块共享内存,然后将之映射到自己的用户空间,之后每隔一秒打印出内存的所有内容。与此同时,writer进程分批向共享内存写入数据。
reader进程的代码:

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>

int main()
{
    int i, sum, shm_id;
    key_t key;
    char *p;

    key = ftok( ".", 'm');
    if(-1 == key)
    {
        perror("ftok error");
        return;
    }

    /* alloc 100 bytes for the shared memory */
    shm_id = shmget( key, 100, IPC_CREAT | S_IRUSR | S_IWUSR);
    if(-1 == shm_id)
    {
        perror("shmget error");
        return;
    }

    /* attach the shared memory */
    p = (char*) shmat( shm_id, NULL, 0);
    if((void*)-1 == p)
    {
        perror("shmat error");
        goto exit0;
    }

    /* clear the space and read it every second */
    //    memset(p, 0, 10);
    do
    {
        printf("\n---------------------------\n");
        printf("pid:%d    key:0x%x    shmid:%d\n", getpid(), key, shm_id);
        for(i = 0 ; i < 10; i++)
        {
            printf("dump[%d] value:%-4d shown:'%c'\n", i, p[i], p[i]);
            if('z' == p[i])
                goto exit1;
        }
        sleep(1);
    }while(1);

exit1:
    system("ipcs -m");
    /* detach */
    if(-1 == shmdt(p))
    {
        perror("shmdt error");
    }
    else
    {
        printf("shmdt ok\n");
    }
exit0:
    system("ipcs -m");
    /* free the shared memory */
    if(-1 == shmctl( shm_id, IPC_RMID, NULL))
    {
        perror("shmctl error");
    }
    else
    {
        printf("shmctl RMID ok\n");
    }
    system("ipcs -m");
    return ;
}

writer进程的代码:

#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
int main(int argc, char *argv[])
{
    int shmid, i;
    char *p;

    if(3 != argc || 0 > (shmid = atoi(argv[1])))
    {
        printf("Usage: %s shmid 01234abcdz\n", argv[0]);
        exit(0);
    }

    /* attach the shared memory */
    p = (char*)shmat( shmid, NULL, 0);
    printf("p=%p, shmid=%d, %s\n", p, shmid, argv[2]);
    if((void*)-1 == p)
    {
        perror("shmat error");
    }
    else
        printf("shmat ok\n");

    /* put sth. in the shared memroy */
    for(i = 0; i < strlen(argv[2]); i++)
    {
        sleep(1);
        p[i] = argv[2][i];
        printf("wrote %d, or shown as '%c'\n", p[i], p[i]);
    }

    /* detach the shared memory */
    if(-1 == shmdt(p))
    {
        perror("shmdt error");
    }
    else
    {
        printf("shmdt successfully\n");
    }

    return ;
}

先运行reader进程,每隔1秒打印共享内存的每一个byte,如果某个byte是字符z就退出。
后运行writer进程,运行时后面跟2个参数,共享内存id和写入的字符串:

user@test:~$ ./writer 1048586 0123abcdz
p=0x7f6dc4e48000, shmid=1048586, 0123abcdz
shmat ok
wrote 48, or shown as '0'
wrote 49, or shown as '1'
wrote 50, or shown as '2'
wrote 51, or shown as '3'
wrote 97, or shown as 'a'
wrote 98, or shown as 'b'
wrote 99, or shown as 'c'
wrote 100, or shown as 'd'
wrote 122, or shown as 'z'
shmdt successfully

由于reader进程显示很多,只截取下最后几段:

---------------------------
pid:18114    key:0x6d046289    shmid:1048586
dump[0] value:48   shown:'0'
dump[1] value:49   shown:'1'
dump[2] value:50   shown:'2'
dump[3] value:51   shown:'3'
dump[4] value:97   shown:'a'
dump[5] value:98   shown:'b'
dump[6] value:99   shown:'c'
dump[7] value:100  shown:'d'
dump[8] value:0    shown:''
dump[9] value:0    shown:''

---------------------------
pid:18114    key:0x6d046289    shmid:1048586
dump[0] value:48   shown:'0'
dump[1] value:49   shown:'1'
dump[2] value:50   shown:'2'
dump[3] value:51   shown:'3'
dump[4] value:97   shown:'a'
dump[5] value:98   shown:'b'
dump[6] value:99   shown:'c'
dump[7] value:100  shown:'d'
dump[8] value:122  shown:'z'

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 32768      user       600        393216     2          dest         
0x00000000 65537      user       600        393216     2          dest         
0x00000000 98306      user       600        393216     2          dest         
0x00000000 360451     user       600        393216     2          dest         
0x00000000 393220     user       600        393216     2          dest         
0x00000000 425989     user       700        16744      2          dest         
0x00000000 294918     user       600        393216     2          dest         
0x00000000 327687     user       700        5273600    2          dest         
0x00000000 491528     user       700        56672      2          dest         
0x6d046289 1048586    user       600        100        1                       

shmdt ok

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 32768      user       600        393216     2          dest         
0x00000000 65537      user       600        393216     2          dest         
0x00000000 98306      user       600        393216     2          dest         
0x00000000 360451     user       600        393216     2          dest         
0x00000000 393220     user       600        393216     2          dest         
0x00000000 425989     user       700        16744      2          dest         
0x00000000 294918     user       600        393216     2          dest         
0x00000000 327687     user       700        5273600    2          dest         
0x00000000 491528     user       700        56672      2          dest         
0x6d046289 1048586    user       600        100        0                       

shmctl RMID ok

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 32768      user       600        393216     2          dest         
0x00000000 65537      user       600        393216     2          dest         
0x00000000 98306      user       600        393216     2          dest         
0x00000000 360451     user       600        393216     2          dest         
0x00000000 393220     user       600        393216     2          dest         
0x00000000 425989     user       700        16744      2          dest         
0x00000000 294918     user       600        393216     2          dest         
0x00000000 327687     user       700        5273600    2          dest         
0x00000000 491528     user       700        56672      2          dest         

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yilonglucky

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值