什么时候调用sem_unlink()?

问题描述 投票:0回答:3

我对 Linux API sem_unlink() 有点困惑,主要是何时或为何调用它。我在 Windows 中使用信号量已经很多年了。在 Windows 中,一旦关闭命名信号量的最后一个句柄,系统就会删除底层内核对象。但在 Linux 中,开发人员需要通过调用 sem_unlink() 来删除内核对象。如果不这样做,内核对象将保留在 /dev/shm 文件夹中。

我遇到的问题是,如果进程 A 调用 sem_unlink() 而进程 B 已锁定信号量,它会立即销毁信号量,现在当/如果进程 C 出现时,进程 B 不再受到信号量的“保护”。更重要的是,手册页充其量也令人困惑:

“信号量名称将立即删除。一旦打开该信号量的所有其他进程关闭该信号量,该信号量就会被销毁。”

如果要等待其他进程关闭信号量,如何才能立即销毁对象?

显然我不明白 Linux 上信号量对象的正确使用。谢谢你的帮助。下面是我用来测试这个的一些示例代码。

int main(void)
{
    sem_t *pSemaphore = sem_open("/MyName", O_CREAT, S_IRUSR | S_IWUSR, 1);
    if(pSemaphore != SEM_FAILED)
    {
        if(sem_wait(pSemaphore) == 0)
        {
            // Perform "protected" operations here

            sem_post(pSemaphore);
        }

        sem_close(pSemaphore);
        sem_unlink("/MyName");
    }

    return 0;
}
linux semaphore
3个回答
14
投票

回复您的问题:

  1. 与 Windows 的信号量行为相比,您 描述一下,POSIX 信号量是内核持久的。这意味着 即使没有进程拥有信号量,信号量仍保留其值 打开。 (信号量的引用计数将为 0)

  2. 如果进程A调用sem_unlink(),而进程B拥有信号量 锁定。这意味着信号量的引用计数不为 0,并且将 不被破坏。

sem_close 与 sem_unlink 的基本操作,我认为将有助于整体理解:

sem_close:close是一个信号量,当进程退出时也会完成。信号量仍然保留在系统中。

sem_unlink:仅当引用计数达到 0 时(即在所有打开它的进程、调用 sem_close 或退出之后), 才会从系统中删除。

参考资料: 书籍 - Unix 网络编程 - 进程间通信,作者:W.Richard Stevens,第 2 卷,第 10 章


5
投票

sem_unlink()
函数删除由名称和标记标识的信号量 一旦所有进程停止使用信号量就会被销毁(这可能意味着 立即,如果所有打开信号量的进程都已关闭它)。


0
投票

我认为最简单的理解方法是将行为与文件和文件句柄进行比较。

  • 当您使用
    open()
    创建/打开文件时,该文件会在文件系统中(通常在磁盘中)创建,并且进程会获得一个 文件句柄,即一个数字。
  • 当您使用
    close()
    关闭文件句柄时,进程将无法再访问该文件,但该文件仍然存在于磁盘上。
  • 当您使用
    unlink()
    删除文件时,如果您使用
    ls
    bash 命令,您将不再在其包含的目录中看到该文件名;然而,仍然可以通过文件句柄访问该文件,并且 inode 仍然存在

这3种情况分别对应

sem_open
sem_close
sem_unlink
sem_t*
对应于文件句柄。

事实上,命名信号量是作为文件实现的

类似地,如果您取消链接信号量而不关闭它,然后创建一个具有相同名称的新信号量,则行为就像您对文件执行相同的操作一样 - 即您将获得两个“具有相同名称”的不同信号量:

#include <fcntl.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <semaphore.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

int main(){
    sem_t *a1 = sem_open("a", O_CREAT | O_EXCL, 0644, 1);
    assert(a1 != SEM_FAILED);
    sem_unlink("a");

    sem_t *a2 = sem_open("a", O_CREAT | O_EXCL, 0644, 2);
    assert(a2 != SEM_FAILED);
    sem_unlink("a");

    int a1value, a2value;
    
    assert(sem_getvalue(a1, &a1value) == 0);
    assert(sem_getvalue(a2, &a2value) == 0);

    assert(a1value == 1);
    assert(a2value == 2);

    sem_close(a1);
    sem_close(a2);
}

这是什么意思?那个

  • 如果您不再需要使用相同名称打开信号量,则可以在打开信号量后立即取消链接。
  • 必须取消链接信号量(至少一次)以避免信号量泄漏,但当进程退出时信号量将被关闭。
© www.soinside.com 2019 - 2024. All rights reserved.