When to call sem_unlink()?
Asked Answered
B

3

17

I'm a little confused by the Linux API sem_unlink(), mainly when or why to call it. I've used semaphores in Windows for many years. In Windows once you close the last handle of a named semaphore the system removes the underlying kernel object. But it appears in Linux you, the developer, needs to remove the kernel object by calling sem_unlink(). If you don't the kernel object persists in the /dev/shm folder.

The problem I'm running into, if process A calls sem_unlink() while process B has the semaphore locked, it immediately destroys the semaphore and now process B is no longer "protected" by the semaphore when/if process C comes along. What's more, the man page is confusing at best:

"The semaphore name is removed immediately. The semaphore is destroyed once all other processes that have the semaphore open close it."

How can it destroy the object immediately if it has to wait for other processes to close the semaphore?

Clearly I don't understand the proper use of semaphore objects on Linux. Thanks for any help. Below is some sample code I'm using to test this.

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;
}
Bottle answered 1/3, 2013 at 18:30 Comment(6)
I think you're reading the manual page wrong. "The semaphore name is removed immediately" means literally what it says - the name is removed so that no further processes can access the semaphore with that name. This does not imply that the semaphore is removed, just the name. The second sentence describes when the semaphore is removed - after every process that currently has it open has closed itPorridge
So I guess the question becomes, at what point do you call sem_unlink() to remove a semaphore? It seems the only way to ensure this works correctly is to leave the semaphore indefinitely on the system. This seems like sloppy programming, but I don't see another solution.Bottle
I think the idea is that you remove it at whatever point you decide you no longer want new processes to be able to attach to it. The system allows processes that are already attached to continue operating, only garbage collecting the resources when the last currently active user goes away. I'm not going to judge whether this is "sloppy" or not, but keep in mind, this is a rather old interface/API, so it may not be "ideal" by today's standards, but it still works for what it was designed for, and thus continues to be useful.Porridge
@twalberg: "the name is removed so that no further processes can access the semaphore with that name. [...] the semaphore is removed after every process that currently has it open has closed it." But if "no further processes can access the semaphore", then they cannot close it. Your phrasing (and the man page's) is confusing, something which occurs all too frequently.Keeper
@Keeper To clarify - no further processes means processes that do not already have an open handle on the semaphore. Those that do have an open handle will still be able to close it, of course, otherwise the reference count could never drop to 0 so that the resources could be released...Porridge
@Porridge I think you made my point: the language is unclear. A better sentence would have been "the name is removed so that no processes can gain access to that semaphore; processes that already have access continue to do so."Keeper
L
15

Response to your questions:

  1. In comparison to the semaphore behavior for windows you describe, POSIX semaphores are Kernel persistent. Meaning that the semaphore retains it's value even if no process has the semaphore opened. (the semaphore's reference count would be 0)

  2. If process A calls sem_unlink() while process B has the semaphore locked. This means the semaphore's reference count is not 0 and will not be destructed.

Basic operation of sem_close vs sem_unlink, I think will help overall understanding:

sem_close: close's a semaphore, this also done when a process exits. the semaphore still remains in the system.

sem_unlink: will be removed from the system only when the reference count reaches 0 (that is after all processes that have it open, call sem_close or are exited).

References: Book - Unix Networking Programming-Interprocess Communication by W.Richard Stevens, vol 2, ch10

Lassiter answered 22/2, 2014 at 23:16 Comment(2)
it is possible to sem_open semaphore in another process since sem_unlink (but sem_close is not called) for this name is called, or it will create new kernel object?Lightfingered
@Lightfingered it creates a new kernel object.Reinstate
G
5

The sem_unlink() function removes the semaphore identified by name and marks the semaphore to be destroyed once all processes cease using it (this may mean immediately, if all processes that had the semaphore open have already closed it).

Garrido answered 3/8, 2016 at 9:32 Comment(1)
Good, I was wondering about that. The man page does not explicitly state what happens if a semaphore is already thoroughly closed when sem_unlink is called. Interestingly, this means the clean-up thread can do either sem_close then sem_unlink, or sem_unlink then sem_close.Keeper
T
0

I think the easiest way to understand is to compare the behavior with files and file handles.

  • When you create/open a file with open(), the file is created in the file system (usually in the disk), and the process get a file handle, namely a number.
  • When you close a file handle with close(), the process no longer have access to that file, however the file still exists on the disk.
  • When you delete a file with unlink(), if you use ls bash command you will no longer see the file name in the directory it's contained it; however the file is still accessible through the file handle, and the inode hangs around.

The 3 cases correspond to sem_open, sem_close and sem_unlink respectively. The sem_t* corresponds to the file handle.

In fact, a named semaphore is implemented as a file.

Analogously, if you unlink a semaphore without closing it, then create a new semaphore with the same name, the behavior is as if you do the same thing with files -- namely that you get two different semaphores "with the same name":

#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);
}

What does this mean? That

  • you can unlink a semaphore right after opening it if you don't need to open it with the same name anymore.
  • you must unlink a semaphore (at least once) to avoid semaphore leak, but semaphores will be closed when the process exits.
Tat answered 31/8, 2023 at 9:0 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.