Why We unlink semaphores before we initializes them?
why we delete a semaphore before initialize it even though the initialization might be the first one.
Because named semaphores such as are created by sem_open()
have kernel persistence. That's part of the point of naming them. They live until either
- they are unlinked and no processes remain that have them open, OR
- the system is shut down.
If you want to be sure you are creating a new (named) semaphore instead of opening an existing one then unlinking the name before the sem_open()
call makes that pretty likely. If you want to be certain, however, then you should also add O_EXCL
to the flags. That will cause sem_open()
to fail if a semaphore with the given name already exists, such as if another process created one between the sem_unlink()
and the sem_open()
.
Note also that semaphore names should begin with a /
(see sem_overview(7)). Some libraries don't enforce that, but you should not gratuitously introduce a portability issue by omitting it.
On the other hand, if you want a semaphore for a single process only, whose lifetime is bounded by its host process, then you are just making life hard on yourself by using named semaphores. You would be better off in that case with anonymous ones, declared as objects of type sem_t
and initialized via the sem_init()
function instead of sem_open()
. That would moot all the persistence and unlinking questions.
Doubts regarding Named Semaphore in C Linux
http://linux.die.net/man/7/sem_overview
"POSIX named semaphores have kernel persistence: if not removed by sem_unlink(3), a semaphore will exist until the system is shut down."
Why is my semaphore on a forked process not being released?
This problem was occurring ultimately because I was calling sem_unlink
on the POSIX semaphore before doing a wait on it in the forked process. Calling sem_unlink
causes the semaphore to be removed when all file descriptors have called sem_close
on the semaphore. This, in essence, prevented my child process from being able to use that instance and be released at all.
This only works sometimes because there is a base assumption that the child is already waiting to be released by the time we call release_child
. This is not guaranteed and was the reason that this was working sometimes and not all the time. If we call release_child
before the child has called sem_wait
then we remove the semaphore completely and the child creates their own version of the semaphore that never gets posted to.
By moving the unlink
call after the if statement in the first set of code, I prevented the child process from removing the semaphore before waiting on it. Also, by removing O_CREAT
flag from the sem_open
in the release_child
and wait_until_released
functions and the sem_unlink
from the release_child
function, I prevented the child from creating their own semaphore.
I wanted to record the behavior that I was seeing though because that was what really caused me problems. In the middle of debugging and fixing this problem I learned that if the parent creates the semaphore but doesn't close it, the child was calling the sem_unlink
and creating it's own version with the same name. This caused me to believe that the original semaphore was still there but that the sem_post
and/or sem_wait
were not working.
So just be aware of your post, wait, close, and unlink calls when you are doing semaphores. Especially when it comes to forked processes!!
Semaphores and shared memory already opened / Problem with O_EXCL flag
Your code, as written, need fail to open a single semaphore only once, and from then on, will never properly sem_unlink
any of the semaphores, so they continue existing for the next program run.
The sequence of events is:
- At some point in development, a
sem_open
fails for whatever reason - The corresponding
sem_close
then fails, and youexit(EXIT_FAILURE);
rather than performing any remainingsem_close
calls and all of thesem_unlink
calls, so the named semaphore continues to exist - On future runs, all
sem_open
calls withO_CREAT
/O_EXCL
fail (because none of them were unlinked), and the problem is never fixed
The simplest solution is to just remove all the exit(EXIT_FAILURE);
calls (perhaps replacing them with debug logging); if the program otherwise ran to completion successfully, cleanup failures aren't that important; it's more important to ensure all the cleanup is performed than to fail-fast when some cleanup fails.
It might also make sense to register separate atexit
handlers for each named semaphore, and only after sem_open
succeeds for that semaphore, so opening one semaphore doesn't register cleanup functions for all of them, nor does a failed open cause you to schedule cleanup. Doing so would reduce the number of failures expected in common failure cases by limiting cleanup to those cases where it is needed.
Named semaphores in C are not deleted after a signal handler call
As @Jonathan said, the SIGTERM signal I use does terminate the process that should clean up the semaphores. By ignoring the signal in the parent process, everything works well.
sem_open fails on second run of program despite successful sem_close call
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;
}
Related Topics
What Does -Prune Option in Find Do
How to Give Highest Priority to Ethernet Interrupt in Linux
Openssl Encoding Errors While Converting Cer to Pem
How to Write Conditional Import Statements in Qml
Use Crontab Job Send Mail, the Email Text Turns to an Attached File Which Named Att00001.Bin
How to Batch Resize Millions of Images to Fit a Max Width and Height
What Is the Use of File Descriptor 255 in Bash Process
How to View and Edit the Ephemeral Port Range on Linux
Xampp: Another Web Server Daemon Is Already Running
Sort by Third Column Leaving First and Second Column Intact in Linux
How to Do Foreach *.Mp3 File Recursively in a Bash Script