如何正确销毁 C 中多个进程使用的共享未命名信号量?

Posted

技术标签:

【中文标题】如何正确销毁 C 中多个进程使用的共享未命名信号量?【英文标题】:How to properly destroy a shared unnamed semaphore used by multiple processes in C? 【发布时间】:2020-07-25 00:15:46 【问题描述】:

我有一个程序,它创建一些共享内存来共享一些数据和一些信号量,在那里写入一些数据,然后其他进程连接到它并读取该数据并执行一些操作,使用由创建的未命名信号量在它们之间进行同步第一个过程。

完成所有操作后,是否只有在所有其他进程都完成后才能销毁信号量(使用 sem_destroy())?或者如果我让第一个进程等待其他进程完成它们的工作然后销毁信号量会更好吗?有了这个,我想我应该实现任何沟通渠道,但不知道该怎么做。

编辑:提供一些代码

这是我创建共享内存简化的编写过程(省略了错误处理):

int fd_shm = shm_open(SHM_NAME, O_RDWR | O_CREAT | O_EXCL,S_IRUSR | S_IWUSR);

/* Resize the memory segment */
ftruncate(fd_shm, sizeof(ShmExampleStruct))

/* Map the memory segment */
ShmExampleStruct *example_struct = mmap(NULL, sizeof(*example_struct), PROT_READ | PROT_WRITE, MAP_SHARED,fd_shm, 0);
close(fd_shm);

sem_init(&(example_struct->sem), 1, 1)

在 ShmExampleStruct 中,我得到了数据和信号量。 在这段代码之后,它将一些数据写入example_struct

而读取过程代码可能是这样的:

/* We open the shared memory */
int fd_shm = shm_open(SHM_NAME, O_RDONLY, 0);

/* Map the memory segment */
ShmExampleStruct *example_struct = mmap(NULL, sizeof(*example_struct), PROT_READ, MAP_SHARED, fd_shm, 0);
close(fd_shm);

然后从 example_struct 中读取一些内容

如果我启动写入进程,然后启动一些读取进程,那么破坏信号量的最佳方法是什么?理论上,写作过程应该在阅读之前开始和结束。

【问题讨论】:

您在使用sem_init 作为您的信号量吗?它们是否与数据位于同一共享内存中?你是如何创建你的共享内存的?请提供一些 C 代码来补充您的问题。 我现在提供了一些代码。是的,我使用 sem_init,信号量与数据位于同一共享内存中,我使用 shm_open、ftruncate 和 mmap 创建共享内存 【参考方案1】:

正如 Michael Kerrish 的 LPI 中所述(第 1103 页),“应在释放其底层内存之前销毁未命名的信号量”。

此外,书中指出“如果信号量驻留在 POSIX 共享内存区域中”,这是您的情况(example_struct->sem),“那么只有在所有进程都没有使用信号量和共享内存对象与shm_unlink()"取消链接之前。

因此,只有在没有进程/线程等待的情况下销毁未命名的信号量才是安全的。它会导致未定义的行为:(1)如果信号量在其他进程/线程被阻塞时被破坏; (2) 如果使用了销毁的信号量。

为了在您的情况下保证这一点,您需要使用shm_unlink() 函数删除共享内存对象,然后才调用sem_destroy()。为此,您需要同步您的进程以安全地销毁信号量。

例如,如果您在父进程中使用fork() 创建进程(读取器和写入器),那么您可以在所有子进程完成后销毁父进程中的共享内存和信号量。对于同步,您可以使用wait() 函数。

【讨论】:

我不知道你的代码是如何构造的,但是如果你遵循fork()wait()的传统方法,你可以在wait()之后清理你的共享内存和信号量。跨度> @XuChen 如果作者和读者独立执行:数据有多少读者/消费者?如果只有一个,那么它可以处理信号量清理。否则,您将必须定义符合条件的 last 进程,并且该进程将进行清理。 @XuChen 如果你有多个阅读器,你如何定义最后一个阅读器,之后可以安全地清理信号量? @XuChen 当然,但说读者现在正在消费数据。这个阅读器如何知道以后是否会有另一个阅读器来读取数据?如果它无法知道,它就无法决定进行清理。我只是指出,这更多是您必须做出的设计决定,然后相应地实施。 @rtx13 啊,对,没想到这种情况。是的,它看起来更像是一个设计决策,而不是一个标准的方法。谢谢你的解释!

以上是关于如何正确销毁 C 中多个进程使用的共享未命名信号量?的主要内容,如果未能解决你的问题,请参考以下文章

正确销毁命名的 System V 信号量

如何在 c 中使用 posix 命名信号量和 Linux 上两个进程之间的共享内存?

在 C 语言中使用 POSIX 在多个进程(不是线程,仅进程)之间共享二进制信号量

正确删除多个进程使用的 SYS V 信号量

使用 posix 未命名信号量的 IPC [关闭]

进程间通信的六大方式