c-信号量和共享内存已打开/O_EXCL标志出现问题



我目前正在开发一个具有共享内存和信号量的程序。然而,我在初始化它们时遇到了问题。每当我想打开它们时(当O_EXCL标志处于活动状态时,我总是会收到错误。这应该意味着它们在启动时已经打开了,但我不知道如何打开或为什么打开。

static sem_t *s1 = NULL;
void initSEM(void)
{
atexit(closeSEM);
s1 = sem_open(SEM_1, O_CREAT | O_EXCL, 0600, 1);
if (s1 == SEM_FAILED)
{
printf("%s", "ERROR: Semaphore 1 could not be opened.");
exit(EXIT_FAILURE);
}
}
void closeSEM(void)
{
if (sem_close(s1) == -1)
{
exit(EXIT_FAILURE);
}
if (sem_close(s2) == -1)
{
exit(EXIT_FAILURE);
}
if (sem_close(s3) == -1)
{
exit(EXIT_FAILURE);
}
if (sem_unlink(SEM_1) == -1)
{
exit(EXIT_FAILURE);
}
if (sem_unlink(SEM_2) == -1)
{
exit(EXIT_FAILURE);
}
if (sem_unlink(SEM_2) == -1)
{
exit(EXIT_FAILURE);
}
}

在我的主函数中,我只调用这个。共享内存也是如此。我不知道为什么会发生这种事。

您的代码在编写时只需要打开一次单个信号量,从那时起,将永远不会正确地sem_unlink任何信号量,因此它们将继续存在以供下一个程序运行。

事件顺序为:

  1. 在开发的某个阶段,sem_open由于任何原因而失败
  2. 相应的sem_close随后失败,您exit(EXIT_FAILURE);而不是执行任何剩余的sem_close调用和所有sem_unlink调用,因此命名信号量继续存在
  3. 在将来的运行中,所有具有O_CREAT/O_EXCLsem_open调用都会失败(因为没有一个调用被取消链接(,而且问题永远不会得到解决

最简单的解决方案是只删除所有exit(EXIT_FAILURE);调用(也许用调试日志记录代替它们(;如果程序以其他方式成功运行完成,那么清除失败就没有那么重要了;确保执行所有清理比在某些清理失败时快速失败更重要。

为每个命名的信号量注册单独的atexit处理程序也是有意义的,并且只有在该信号量的sem_open成功之后,因此打开一个信号量不会为所有信号量注册清理函数,打开失败也不会导致您计划清理。这样做可以将清理限制在需要的情况下,从而减少常见故障情况下预期的故障数量。

最新更新