尽管 sem_close 调用成功,但 sem_open 在程序的第二个 运行 上失败

sem_open fails on second run of program despite successful sem_close call

我正在使用 sem_opensem_close 来创建和销毁信号量,因为 sem_init and sem_destroy are deprecated on OS X

我第一次 运行 我的程序,信号量按预期运行。在我的程序结束时,我调用 sem_close 并且它 returns 没有错误。

但是,如果我再次 运行 程序,sem_open 失败 errno EEXIST:

Both O_CREAT and O_EXCL were specified in oflag, but a semaphore with this name already exists.

不仅 sem_close 函数 return 在第一个 运行 期间成功,而且 the man file 表明信号量在进程终止时关闭,而不管:

All open named semaphores are automatically closed on process termination

所以我对为什么信号量持续存在感到困惑。

MCVE

// file: pc.cc
#include <semaphore.h>
#include <pthread.h>
#include <cstdio>
#include <cstdlib>
#include <errno.h>

int main(int argc, char *argv[])
{
    errno = 0;
    sem_t *semaphore = sem_open("/sem3", O_CREAT | O_EXCL, 0, 0);

    if (semaphore == SEM_FAILED) {
        int err1 = errno;
        fprintf(stderr, "sem_open() failed.  errno:%d\n", err1);
        if (EEXIST == err1)
            fprintf(stderr, "EEXIST : Both O_CREAT and O_EXCL were specified in oflag, but a semaphore with this name already exists. \n");
    }

    errno = 0;
    if(sem_close(semaphore) == -1){
        int err2 = errno;
        fprintf(stderr, "sem_close() failed. errno:%d\n", err2);
        if( EINVAL == err2)
            fprintf(stderr, "EINVAL : sem is not a valid semaphore.");

    }

    return 0;
}

第一个和第二个的输出运行

$ ./output_test
$ ./output_test
    sem_open() failed.  errno:17
    EEXIST : Both O_CREAT and O_EXCL were specified in oflag, but a semaphore with this name already exists. 
    sem_close() failed. errno:9

我需要同时使用 sem_closesem_unlink. This was mentioned in sem_init on OS X, but I missed the significance. This answer 帮助详细说明何时使用每个功能。求和:

sem_close 只释放信号量使用的资源。关闭的信号量持续存在并且可以重新打开。

sem_unlink 标记信号量在所有进程停止使用时销毁。

正如@JohnBollinger 在评论中添加的那样,

If you need the semaphore only for the duration of one run of one program, then you should consider unlinking it (via sem_unlink()) immediately after creating it. You can then continue to use it until you close it, but it will not block other instances of the program from using the same semaphore name. Moreover, since open semaphores are closed but not automatically unlinked when the program exits, that protects you from having the semaphore hang around in the event that your program crashes before unlinking it.

示例解决方案

// file: pc.cc
#include <semaphore.h>
#include <pthread.h>
#include <cstdio>
#include <cstdlib>
#include <errno.h>

int main(int argc, char *argv[])
{
    errno = 0;
    sem_t *semaphore = sem_open("/sem5", O_CREAT | O_EXCL, 0, 0);
    sem_unlink("/sem5"); //Unlink to ensure semaphore is destroyed if program crashes

    if (semaphore == SEM_FAILED) {
        int err1 = errno;
        fprintf(stderr, "sem_open() failed.  errno:%d\n", err1);
        if (EEXIST == err1)
            fprintf(stderr, "EEXIST : Both O_CREAT and O_EXCL were specified in oflag, but a semaphore with this name already exists. \n");
    }

    //The semaphore will be closed when the program exits, but can also close it explicitly.
    errno = 0;
    if(sem_close(semaphore) == -1){
        int err2 = errno;
        fprintf(stderr, "sem_close() failed. errno:%d\n", err2);
        if( EINVAL == err2)
            fprintf(stderr, "EINVAL : sem is not a valid semaphore.");

    }

    return 0;
}