Search code examples
arrayscposixsemaphore

How to unlink/close an array of named semaphores in C


I am trying to create an array of N named POSIX semaphores in C. But I am having trouble unlinking and closing them. I need to use an array of semaphores because each semaphore will represent a segment of a text file that will later go into shared memory.

I am doing something very similar to this post but it is not working. Maybe the problem is in the creation of the semaphores? Is there another way I could do this?

sem_t* semaphores[N];

for(int i = 0; i < N; i++){
    char buf[100];
    sprintf(buf, "s%d", i);       // Give a unique name to each semaphore
    semaphores[i] = sem_open(buf, O_CREAT | O_EXCL, SEM_PERMS, INITIAL_VALUE);
}

for(int i = 0; i < N; i++){
    if(sem_unlink((void*)semaphores[i]) < 0){
        perror("sem_unlink(0) failed OVER HERE");
        exit(EXIT_FAILURE);
    }
 }

for(int i = 0; i < N; i++){
    if(sem_close(semaphores[i]) < 0){
        perror("sem_close(0) failed HERE");
        exit(EXIT_FAILURE);
    }
 }

The error message I am getting is:

sem_unlink(0) failed OVER HERE: No such file or directory


Solution

  • While sem_close(3) takes a sem_t * argument, sem_unlink(3) takes the name of the semaphore as a const char *.

    Retain the names of your semaphores, so that they may be passed to sem_unlink(3) later. The example below uses an array of structures to do so.

    Additionally, per sem_overview(7), semaphore names should begin with a leading /.

    #include <fcntl.h>
    #include <semaphore.h>
    #include <stdio.h>
    
    #define INITIAL_VALUE 1
    #define N 8
    #define SEM_PERMS 0666
    
    int main(void)
    {
        struct {
            char name[128];
            sem_t *sem;
        } semaphores[N];
    
        for (size_t i = 0; i < N; i++) {
            sprintf(semaphores[i].name, "/a-semaphore%zu", i);
            semaphores[i].sem = sem_open(semaphores[i].name,
                    O_CREAT | O_EXCL, SEM_PERMS, INITIAL_VALUE);
    
            if (SEM_FAILED == semaphores[i].sem)
                perror(semaphores[i].name);
        }
    
        for (size_t i = 0; i < N; i++)
            if (sem_unlink(semaphores[i].name) < 0)
                perror(semaphores[i].name);
    
        for (size_t i = 0; i < N; i++)
            if (sem_close(semaphores[i].sem) < 0)
                perror(semaphores[i].name);
    }
    

    As John points out below, storing each name is not necessarily required. Since the names are algorithmically generated, you could regenerate them from the same template when they are needed again.

    A cursory example:

    #include <fcntl.h>
    #include <semaphore.h>
    #include <stdio.h>
    
    #define INITIAL_VALUE 1
    #define N 8
    #define SEM_PERMS 0666
    
    void namegen(char *dst, size_t suffix)
    {
        sprintf(dst, "/a-semaphore%zu", suffix);
    }
    
    int main(void)
    {
        sem_t *semaphores[N];
    
        for (size_t i = 0; i < N; i++) {
            char name[128];
            namegen(name, i);
    
            semaphores[i] = sem_open(name,
                    O_CREAT | O_EXCL, SEM_PERMS, INITIAL_VALUE);
    
            if (SEM_FAILED == semaphores[i])
                perror(name);
        }
    
        for (size_t i = 0; i < N; i++) {
            char name[128];
            namegen(name, i);
    
            if (sem_unlink(name) < 0)
                perror(name);
    
            if (sem_close(semaphores[i]) < 0)
                perror(name);
        }
    }