宝运莱手机版 - 最新网上娱乐平台 当前位置:首页>宝运莱手机版 - 最新网上娱乐平台>正文

宝运莱手机版 - 最新网上娱乐平台

发布时间:2019-03-25

原标题:Linux进程间通信-共享内存

脑域一号也不恼,她将吸管给叶扬拿来以后,然后问道:“你真的一点也不能动了?”

乐通娱乐&首页

“呵呵,六式吗?这只是我学会的一种体技罢了,不过卡普我和你一样,都是用身体去战斗的,六式我也打算用一下,不过这毕竟是别人的,用这个来对付你好像太过小看你了吧,有点班门弄斧,有没有兴趣和我自己开发的绝技比一下。”
“朱元璋这个人可是很有才能的,只可惜这种人是典型的白眼狼,虽说帝皇无情,但是无情到他这个地步真的很少见,和他在一起的所谓兄弟都只能共患难而不能富贵,一旦他达到了自己的目的,昔日的兄弟手足他都会直接舍去。”

而且根据神侯提供的资料,这皇级强者就快要诞生了,他得把这件事赶紧的向龙祖他们报告。

继前三篇分析了进程间通信机制管道,命名管道(FIFO),消息队列后,本文将介绍最后一种进程间通信机制,也是进程间通信机制效率最高的一种-共享内存

1、共享内存

考虑前三种进程间通信机制,一个客户-服务器文件复制程序将设计到一下步骤:

(1)服务器从输入文件读取。该文件的数据由内核读入自己的内存空间,然后从内核复制到服务器进程。

(2)服务器往管道、FIFO和消息队列以一条消息的形式写入这些数据。这些IPC形式需要把进程中的数据复制到内核。

(3)客户端从这些IPC通道中读取数据,需要把内核数据复制到进程的地址空间。

(4)客户端将进程空间内的数据再写入内核,由内核写入文件。

 

 这些IPC形式的问题在于,共享数据需要多次经过内核。

 

共享内存的方式是让同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制(Linux同步的机制系列文章)。同样是上面的例子,共享内存只需经过如下 流程:

这种形式的通信数据只需复制两次:一次从输入文件到共享内存,另一次是从共享内存到输出文件。

2、共享内存基本操作

2.1 打开/创建一个共享内存对象

#include <sys/mman.h>

int shm_open(const char* name, int oflag, mode_t mode);

成功返回非负描述符,若失败返回-1

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>

int main(int argc, char* argv[])
{
    int flag = O_RDWR | O_CREAT | O_EXCL;
    int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
    int fd = 0;
    fd = shm_open("/shm_test", flag, mode);
    if (-1 == fd)
    {
        printf("open shm failed!
");
        return 1;
    }
    ftruncate(fd, 1024);

    mmap(NULL,1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    return 0;
}

 

 

2.2 删除一个共享对象的名字

#include <sys/mman.h>

int shm_unlink(const char* name);

成功返回0,失败返回-1

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>

int main(int argc, char* argv[])
{
    shm_unlink("/shm_test");
    return 0;
}

 

2.3 ftruncate 和 fstat

处理mmap的时候,普通文件或共享内存对象的大小可以通过ftruncate函数修改:

#include <unistd.h>

int ftruncate(int fd, off_t length);

成功返回0,出错返回-1

 

当打开一个已存在的共享内存区对象时,我们可调用fstat来获取有关该对象的信息:

#include <sys/types.h>

#include <sys/stat.h>

int fstat(int fd, struct stat* stat);

成功返回0,失败返回-1

对于普通文件stat结构可以获得12个以上的成员信息,然而当fd指代一个共享内存区对象时,只有四个成员含有信息。

struct stat{

...

mode_t st_mode;

uid_t st_uid;

gid_t st_gid;

off_t st_size;

};

 2.4 共享内存的读写

read端代码如下:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>

int main(int argc, char* argv[])
{
    int flag = O_RDONLY;
    int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
    int fd = 0;
    unsigned char* ptr, c;
    fd = shm_open("/shm_test", flag, mode);
    if (-1 == fd)
    {
        printf("open shm failed!
");
        return 1;
    }
    struct stat stat; 
    fstat(fd,&stat);
    ptr = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
    close(fd);

    for (int i = 0; i < stat.st_size; i++)
    {
        if((c = *ptr++) != (i%256))
        {
            printf("read error!
");
            exit(-1);
        }
        else{
            printf("%c
",c);
        }
    }

    return 0;
}

 

 

 

write端代码如下:

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>

int main(int argc, char* argv[])
{
    int flag = O_RDWR;
    int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
    int fd = 0;
    unsigned char* ptr, c;
    fd = shm_open("/shm_test", flag, mode);
    if (-1 == fd)
    {
        printf("open shm failed!
");
        return 1;
    }
    struct stat stat; 
    fstat(fd,&stat);
    ptr = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    close(fd);

    for (int i = 0; i < stat.st_size; i++)
    {
        *ptr++ = i % 256;
        printf("write %d
",i);
    }
    return 0;
}

 

这里与mqueue不同的是,read端读取的时候并不会阻塞等待,如果没有提前write内容到共享内存里,read读取到的内容为空。

3、共享内存的起始地址

同一共享内存区对象映射到不同进程的地址空间,起始地址可以不一样。

#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdio.h>
#include <sys/wait.h>
#include <errno.h> 
#include <string.h>

int main(int argc, char* argv[])
{
    int fd1,fd2;
    unsigned char *ptr1, *ptr2;
    pid_t pid;
    int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
    fd1 = shm_open("/shm_test",O_RDWR,mode);
    if (fd1 == -1)
    {
        printf("Message : %s
", strerror(errno)); 
        return 1;
    }

    struct stat stat;
    fstat(fd1, &stat);

    fd2 = open("/dev/shm/shm_test1",O_RDWR | O_CREAT,mode);
    if (fd2 == -1)
    {
        printf("Message : %s
", strerror(errno)); 
        return 1;
    }
    
    pid = fork();
    if (pid == 0)
    {
        ptr2 = mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED, fd2,0);
        ptr1 = mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
        printf("child: shm ptr=%p, mmf ptr=%p
",ptr1, ptr2);
        sleep(5);
        printf("share memory integer:%d", *ptr1);
    }
    else if (pid > 0)
    {
        ptr1 = mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
        ptr2 = mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED, fd2,0);
        printf("parent: shm ptr=%p, mmf ptr=%p
",ptr1, ptr2);
        *ptr1 = 128;
        waitpid(0, NULL, 0);
    }
    else{
        
    }

    return 0;
}

 

 代码运行结果如下:

可见,在不同的进程中,相同的共享内存区对象起始地址可以不一样。 

 

编辑:华海帝

发布时间:2019-03-25 02:30:18

当前文章://6mfp7.html

千赢国际 - 点此进入 云顶娱乐|手机版 无线娱乐2 优乐pt客户端下载 

责任编辑:帝海建马