POSIX Semaphores Closing and Removing Named Semaphores: sem_close() & sem_unlink()

 

POSIX Semaphores โ€“ Part 2
Closing and Removing Named Semaphores: sem_close() & sem_unlink()
๐Ÿ“˜ Chapter 53 โ€“ TLPI
๐Ÿ”ง Linux IPC
๐ŸŽฏ Intermediate Level

What This Tutorial Covers

After creating and opening a named POSIX semaphore, you need to properly close it when your process is done, and eventually remove it from the system when no one needs it anymore. These two operations โ€” sem_close() and sem_unlink() โ€” are the focus of this tutorial. We will understand what each one does, how they differ, and practice with real code examples.

Key Terms:

sem_close() sem_unlink() Named Semaphore sem_t semaphore.h Process Termination exec() Reference Count

1. Closing a Named Semaphore โ€“ sem_close()

When a process opens a named semaphore using sem_open(), the operating system internally records the link between that process and the semaphore. Think of it as the OS keeping a reference count โ€” how many processes currently have this semaphore open.

Calling sem_close() tells the OS: “This process is done using this semaphore.” It does three things:

  • Terminates the association between this process and the semaphore
  • Frees any OS resources allocated for this process’s access to the semaphore
  • Decrements the internal reference count of the semaphore

Named Semaphore Lifecycle
sem_open()
Open / Create
ref_count++
sem_close()
Close access
ref_count–
sem_unlink()
Remove from FS
destroy when ref=0
โš ๏ธ sem_close() โ‰  sem_unlink(). Closing does NOT delete the semaphore!

Function Signature

#include <semaphore.h>

int sem_close(sem_t *sem);
/* Returns 0 on success, or -1 on error */

Important Behaviour

You do not need to explicitly call sem_close() in all situations. Named semaphores are automatically closed in two cases:

  • When the process terminates (normal exit or crash)
  • When the process calls exec() to execute a new program

However, it is always good practice to call sem_close() explicitly. This frees resources promptly and avoids resource leaks in long-running processes.

Code Example โ€“ Closing a Semaphore

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <fcntl.h>   /* O_CREAT, O_RDWR */
#include <sys/stat.h>

int main(void)
{
    sem_t *sem;

    /* Open an existing named semaphore (must already exist) */
    sem = sem_open("/my_semaphore", 0);
    if (sem == SEM_FAILED) {
        perror("sem_open");
        exit(EXIT_FAILURE);
    }

    printf("Semaphore opened successfully.\n");

    /* ... do some work with the semaphore ... */

    /* Close the semaphore when done โ€” releases resources for this process */
    if (sem_close(sem) == -1) {
        perror("sem_close");
        exit(EXIT_FAILURE);
    }

    printf("Semaphore closed. It still exists in the system.\n");
    printf("Use sem_unlink() to actually delete it.\n");

    return EXIT_SUCCESS;
}
๐Ÿ’ก Key Point: After sem_close(), the semaphore still exists in the filesystem (under /dev/shm/ on Linux). Other processes can still open and use it. Only sem_unlink() actually removes it.

2. Removing a Named Semaphore โ€“ sem_unlink()

sem_unlink() removes the named semaphore from the filesystem. It is similar in concept to unlink() for files. However, like file unlinking, the semaphore is not immediately destroyed if other processes still have it open.

The exact behaviour is:

  • The name is removed from the filesystem immediately
  • No new processes can open the semaphore using this name
  • The semaphore object is destroyed only when all currently open references are closed

sem_unlink() Behaviour
Case 1: No other process has it open

sem_unlink(“/sem”) is called
โ†“
Name removed from /dev/shm
โ†“
Semaphore object destroyed immediately

Case 2: Other processes still have it open

sem_unlink(“/sem”) is called
โ†“
Name removed from /dev/shm
โ†“
Object stays alive until all sem_close() calls complete

Function Signature

#include <semaphore.h>

int sem_unlink(const char *name);
/* Returns 0 on success, or -1 on error */

Code Example โ€“ Unlinking a Semaphore

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>

int main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <sem-name>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    /* Remove the named semaphore identified by argv[1] */
    if (sem_unlink(argv[1]) == -1) {
        perror("sem_unlink");
        exit(EXIT_FAILURE);
    }

    printf("Semaphore '%s' unlinked successfully.\n", argv[1]);
    return EXIT_SUCCESS;
}

Code Example โ€“ Full Lifecycle (Create โ†’ Use โ†’ Close โ†’ Unlink)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/stat.h>

#define SEM_NAME "/demo_sem"

int main(void)
{
    sem_t *sem;

    /* Step 1: Create and open the semaphore with initial value 1 */
    sem = sem_open(SEM_NAME, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 1);
    if (sem == SEM_FAILED) {
        perror("sem_open");
        exit(EXIT_FAILURE);
    }
    printf("Step 1: Semaphore created: %s\n", SEM_NAME);

    /* Step 2: Use the semaphore (wait = lock, post = unlock) */
    if (sem_wait(sem) == -1) {
        perror("sem_wait");
        exit(EXIT_FAILURE);
    }
    printf("Step 2: Entered critical section\n");

    /* ... critical section work ... */

    if (sem_post(sem) == -1) {
        perror("sem_post");
        exit(EXIT_FAILURE);
    }
    printf("Step 3: Exited critical section\n");

    /* Step 4: Close this process's access */
    if (sem_close(sem) == -1) {
        perror("sem_close");
        exit(EXIT_FAILURE);
    }
    printf("Step 4: Semaphore closed\n");

    /* Step 5: Remove the semaphore from the system */
    if (sem_unlink(SEM_NAME) == -1) {
        perror("sem_unlink");
        exit(EXIT_FAILURE);
    }
    printf("Step 5: Semaphore unlinked and destroyed\n");

    return EXIT_SUCCESS;
}
โš ๏ธ Compile flag required: Always link with -lrt or -lpthread depending on your system:
gcc program.c -o program -lpthread

3. sem_close() vs sem_unlink() โ€“ Side by Side
Aspect sem_close() sem_unlink()
What it does Closes this process’s handle to the semaphore Removes the semaphore name from the filesystem
Argument sem_t * (pointer) const char * (name)
Deletes semaphore? โŒ No โœ… Yes (when all refs close)
Auto-called? Yes, on exit() or exec() No, must be called explicitly
Analogy Like close(fd) for files Like unlink(path) for files

๐ŸŽฏ Interview Questions โ€“ Closing & Removing Semaphores
Q1: What is the difference between sem_close() and sem_unlink()?

A: sem_close() closes the calling process’s access to the semaphore and releases resources held by that process. The semaphore still exists in the system and other processes can continue using it. sem_unlink() removes the semaphore’s name from the filesystem so no new process can open it. The semaphore object is actually destroyed only after all processes that have it open call sem_close() or terminate.

Q2: Is it necessary to call sem_close() before sem_unlink()?

A: No, there is no required order. You can call sem_unlink() at any time โ€” even while processes still have the semaphore open. The name is removed immediately but the object persists until the last open reference is closed. Calling sem_close() first is good practice but not mandatory.

Q3: What happens to a named semaphore when a process crashes without calling sem_close()?

A: The OS automatically closes the semaphore on behalf of the process when the process terminates (by any means including crash). So the reference count is decremented. However, if sem_unlink() was never called, the semaphore name persists in the filesystem even after all processes exit, and it will still be there the next time the system runs.

Q4: Where are named semaphores stored on Linux?

A: On Linux, named semaphores are stored under /dev/shm/ as files with the prefix sem.. For example, sem_open("/my_sem", ...) creates /dev/shm/sem.my_sem. You can list them with ls /dev/shm/.

Q5: Does exec() close named semaphores?

A: Yes. Named semaphores are automatically closed if the process calls any exec() variant. This is similar to file descriptors with the FD_CLOEXEC flag set. The new program started by exec() does not inherit the semaphore handles.

Q6: What error does sem_unlink() return if the semaphore name does not exist?

A: sem_unlink() returns -1 and sets errno to ENOENT (No such file or directory) if the specified name does not exist.

Leave a Reply

Your email address will not be published. Required fields are marked *