首页 > 解决方案 > 信号量和共享内存已打开/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);
    }
}

在我的主要功能中,我只是称之为。共享内存也是如此。我不知道为什么会这样。

标签: cmultithreadingsemaphoreshared-memory

解决方案


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

事件的顺序是:

  1. 在开发的某个时刻,sem_open无论出于何种原因失败
  2. 相应的sem_closethen 失败,并且您exit(EXIT_FAILURE);而不是执行任何剩余的调用sem_close所有sem_unlink调用,因此命名信号量继续存在
  3. 在以后的运行中,所有sem_open调用O_CREAT/O_EXCL失败(因为它们都没有被取消链接),并且问题永远不会解决

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

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


推荐阅读