Reputation: 332
I am trying to initialize a binary semaphore for some shared memory. I could not figure out why I hung on a semop to get the semaphore, and eventually found that the semaphore value was -1 and I was stuck waiting. What I don't get is why the semaphore value is initializing to -1 to begin with. Any help clarifying this would be greatly appreciated.
semID = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR); // create sem
int semval = semctl(semID, 1,GETVAL);
printf("After init Semaphore value = %d \n", semval);
printf("sem ID = %d \n", semID);
Output :
After init semaphore value = -1
sem ID = 524304
Upvotes: 1
Views: 1522
Reputation: 140579
You have two bugs. Your first bug is that, as always in C, the array of semaphores created by semget
is 0-indexed; so, if you create only one semaphore, the second argument to semctl
with that semid
should be 0, not 1. The -1 you're getting back from semctl
is not the value of the semaphore, but an error indication (you should find that errno == EINVAL
).
Your second bug is more subtle. The POSIX.1-2008 specification for semget
says:
Upon creation, ...
- the data structure associated with each semaphore in the set need not be initialized. The
semctl()
function with the commandSETVAL
orSETALL
can be used to initialize each semaphore.
(emphasis mine) What that means is, your code cannot rely on a new SysV semaphore having any specific value when it's first created. You have to do something like this:
semID = semget(IPC_PRIVATE, 1, S_IRUSR|S_IWUSR);
if (semID < 0) {
perror("semget");
return -1;
}
union semun arg;
arg.val = 0;
if (semctl(semID, 0, SETVAL, arg) == -1) {
perror("semctl");
return -1;
}
// only now is it safe to use the semaphore
Note that you have to copy the definition of union semun
out of the documentation into your code; it is not provided by any header.
If you're starting to get the feeling that this API is terrible, you are 100% correct. You may find the semaphore.h
API more congenial, however it is less widespread.
Upvotes: 4
Reputation: 1906
Actually, the man page for semctl tells you that a return value of -1 means there was an error.
To get the error use strerror printf( "%s", strerror(errno) );
Don't forget #include <errno.h>
and #include <string.h>
Upvotes: 2