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.
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;
}
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.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 |
Case 2: Other processes still have it open
sem_unlink(“/sem”) is called |
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;
}
-lrt or -lpthread depending on your system:gcc program.c -o program -lpthread| 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 |
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.
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.
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.
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/.
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.
A: sem_unlink() returns -1 and sets errno to ENOENT (No such file or directory) if the specified name does not exist.
