我正在尝试为某些共享内存初始化二进制信号量。我无法弄清楚为什么我挂在semop上获取信号量,最终发现信号量值为-1而且我等待了。我没有得到的是为什么信号量值初始化为-1开始。任何澄清这一点的帮助将不胜感激。
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);
输出:
After init semaphore value = -1
sem ID = 524304
答案 0 :(得分:4)
你有两个错误。你的第一个错误是,就像在C中一样,由semget
创建的信号量数组是0索引的;所以,如果你只创建一个信号量,semctl
与semid
的第二个参数应为0,而不是1.你从semctl
回来的-1不是信号量的值,但是错误指示(你应该找到errno == EINVAL
)。
你的第二个错误更微妙。 The POSIX.1-2008 specification for semget
说:
创作后......
- 与集合中每个信号量相关联的数据结构无需初始化。使用命令
SETVAL
或SETALL
的{{3}}函数可用于初始化每个信号量。
(强调我的)这意味着,您的代码在首次创建时不能依赖具有任何特定值的新SysV信号量。你必须做这样的事情:
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
请注意,您必须将文档中的union semun
定义复制到您的代码中;它不是由任何标题提供的。
如果你开始觉得这个API很糟糕,那么你是100%正确的。您可能会发现semctl()
API更适合,但 不太普遍。
答案 1 :(得分:2)
实际上,man page for semctl告诉您返回值为-1表示存在错误。
要使用strerror printf( "%s", strerror(errno) );
别忘了#include <errno.h>
和#include <string.h>