2

I'm using sem_open and sem_close to create and destroy semaphores because sem_init and sem_destroy are deprecated on OS X.

The first time I run my program, the semaphore functions as expected. At the end of my program, I call sem_close and it returns without an error.

However, if I run the program again, sem_open fails with errno EEXIST:

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

Not only did the sem_close function return successfully during the first run, but the man file suggests that the semaphores are closed on process termination regardless:

All open named semaphores are automatically closed on process termination

So I am mystified as to why the semaphore persists.

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 from first and second run

$ ./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
Cecilia
  • 4,512
  • 3
  • 32
  • 75
  • 1
    Note that the word you are looking for is "*deprecated*". "Depreciated" is something altogether different. – John Bollinger Sep 18 '17 at 19:25
  • 1
    @JohnBollinger This is honestly the first time that I noticed the difference in spelling. Because features are often deprecated in new versions, I assumed that they had "lost value over time". It never occurred to me that they were "disapproved of". :) – Cecilia Sep 18 '17 at 19:39

1 Answers1

3

I need to use both sem_close and sem_unlink. This was mentioned in sem_init on OS X, but I missed the significance. This answer helps detail when to use each function. To summerize:

sem_close only frees the resources used by the semaphore. A closed semaphore persists and can be reopened.

sem_unlink marks the semaphore to be destroyed when all processes stop using it.

As @JohnBollinger added in the comments,

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.

Example Solution

// 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;
}
Cecilia
  • 4,512
  • 3
  • 32
  • 75
  • So is this a complete self-answer, then? If so, then congratulations on solving the problem yourself, and thanks for telling us how you did so. Note, however, that if you meant to revise the question rather than answer it yourself then that would be accomplished by actually editing the question. – John Bollinger Sep 18 '17 at 19:52
  • It's a complete self answer. I've changed the code header to make that more clear. (I can't accept it for another 2 days) If I got any details wrong, please let me know. – Cecilia Sep 18 '17 at 19:54
  • 3
    You only mention only one program. 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. – John Bollinger Sep 18 '17 at 20:15
  • @JohnBollinger Thanks, that's a definite improvement. – Cecilia Sep 18 '17 at 20:35
  • @JohnBollinger Just trying to understand the concept better. When a process crashes, what's the advantage of the semaphore getting destroyed but the name staying around? When you call `sem_open` again with the same name, the original semaphore would still be returned, no? – legends2k Apr 11 '22 at 14:32
  • @JohnBollinger When you immediately unlink after creating, another instance of the same process would also be able to create a _different_ semaphore with the same name. How is that useful? Auto-unlinking OTOH would've been a useful feature (though unavailable) to create single-instance apps; when a process crashes without properly unlinking the semaphore it'd be taken care of. – legends2k Apr 11 '22 at 14:36
  • 1
    Yes, @legends2k, unlinking immediately after creating allows another instance of the same program to create a different semaphore with the same name. That is often *precisely* what one wants: each instance of the program with its own semaphore, not interfering with each other. Multiple threads of the process can use it to synchronize, or multiple processes that inherit it across a `fork()`. But this is admittedly a bit of a half measure, as usually such cases are better handled with an unnamed semaphore instead of named one. – John Bollinger Apr 11 '22 at 14:42
  • @legends2k, a named semaphore that has not been unlinked is not destroyed when the process that created it terminates, regardless of the nature of the termination. The advantage of this is that other processes can open and use it. You can think of it as analogous to creating a file on the file system. – John Bollinger Apr 11 '22 at 14:45
  • @JohnBollinger You're right, I was thinking of using named semaphores for making a single-instance app where it isn't a robust approach but I see where it can be useful though. Thanks for the comments. – legends2k Apr 12 '22 at 05:50