在线程中创建posix共享内存

Posted

技术标签:

【中文标题】在线程中创建posix共享内存【英文标题】:posix shared memory creation in thread 【发布时间】:2018-11-30 03:50:40 【问题描述】:

我是 Linux 编程的新手,所以请温柔一点! .

我正在尝试实现上述场景。这里使用fork() 创建了两个进程,每个进程都有N 个线程。 来自进程 1 的线程创建一个请求并将其加入队列 1。来自进程 2 的线程将一个请求出列并在队列 2 上发回响应。 每个请求由shmidsize 组成,其中shmid 是这样生成的共享内存段 -

shmid = shm_open(<a random string>, O_CREAT | O_RDWR | O_TRUNC, S_IRWXU | S_IRWXG);

if (shmid < 0) 
    perror("failure on shm_open");
    exit(1);

if (ftruncate(*share, size) == -1) 
    perror("Error on ftruncate\n");
    exit(-1);

我可以在创建后立即在同一个线程中打开和修改这个共享内存段

void* request = mmap(NULL, size, PROT_WRITE, MAP_SHARED, shmid, 0);
memset(str, 'w', size);

在此之后,我使用队列 1 将 shmid 传递给进程 2。

我的问题是,当进程 2 中的线程尝试使用相同的方式打开此 shmid 时,我收到 EBADF: fd is not a valid file descriptor 错误。我已经通过在进程 1 和 2 中打印值来验证出队后 shmid 是正确的。

当从不同的进程/线程创建进程时,是否无法在进程之间创建共享内存段?关于如何让它发挥作用的任何想法?

如果需要更多信息,请告诉我。

【问题讨论】:

为什么不使用消息队列呢? Unix 消息队列而不是队列?我将来可能会切换到那个。但这对我目前的问题有帮助吗?我不认为他们是相关的...... Posix 消息队列,是的。 linux.die.net/man/7/mq_overview 或其他人建议的 Unix 本地数据报套接字。为什么要通过重新发明***来让生活变得困难?使用现有的消息传递功能。 【参考方案1】:

共享内存段必须在两个进程中都打开。

如果两个进程都是由fork()从一个共同的父进程创建的,那么您可以在fork()之前执行shm_open(),它将被两个子进程继承。

另外,每个进程都可以调用shm_open(),为name 参数传递相同的值。

【讨论】:

我一直在寻找替代解决方案!我的请求有可变大小,所以我不知道分配 pre-fork() 的大小。谢谢! P.S.第二次打开共享内存时,打开它时不要设置O_TRUNC 标志。 O_TRUNC 将共享内存对象截断为 0 字节。来源 - man7.org/linux/man-pages/man3/shm_open.3.html【参考方案2】:

如果您试图访问由另一个进程创建的文件描述符,它将无法正常工作。文件描述符仅在创建它们的过程中有效。我之所以这么说是因为您看到的错误。

但是您对共享内存有正确的想法,您可以为两个进程创建一个共享的映射内存段,这可能会因竞争条件而变得棘手,每个进程中的多个线程竞争访问它,或者您可以创建一个套接字,并让您的两个进程通过该套接字或管道进行通信。

我会推荐一个用于 IPC 的 AF_UNIX 套接字,就像您尝试实现的那样。

【讨论】:

是的,如果使用队列不成功,我将不得不切换到套接字。我实施队列的唯一原因是因为它在我的要求中有所说明...... 我在想你可以在映射的内存块的头部放置一个互斥锁,然后来自两个进程的线程可以锁定和解锁。只是一个想法。 是的,我已经这样做了。我已将 posix 互斥锁和条件变量映射到共享内存,并使用它进行同步。

以上是关于在线程中创建posix共享内存的主要内容,如果未能解决你的问题,请参考以下文章

一个用户崩溃时共享内存中的互斥锁?

信号量

POSIX 共享内存 - 有多少个内存副本

Posix共享内存

linux c编程:Posix共享内存区

Posix 共享内存与映射文件