我正在尝试启动UNIX信号灯,以便可以使用它来控制两个进程。
我复制了this示例中的sem_init
函数。我删除了pshared
参数,因为该参数未在函数中使用,并假设这是一个错误,将int * sem
更正为int * semid
。
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <errno.h>
/* The semaphore key is an arbitrary long integer which serves as an
external identifier by which the semaphore is known to any program
that wishes to use it. */
using namespace std;
#define KEY (1492)
int sem_init(int* semid, unsigned int value) {
/* get the semaphore */
*semid = semget(KEY, 1, IPC_CREAT);
if (*semid == -1) {
printf("Unable to obtain semaphore.\n");
return -1;
}
int ret = semctl( *semid, 0, SETVAL, value);
if (ret == -1) {
printf("Unable to set semaphore value: %s\n", strerror(errno));
return -1;
}
return ret;
}
int main(void) {
int* semid = (int*) malloc(sizeof(int));
sem_init(semid, 1);
return 0;
}
程序将打印Unable to set semaphore value: permission denied
。我还复制了this示例中的第一个主函数,并显示了Cannot set semaphore value
。
我应该提到的一件事是,似乎在以前运行该程序的背景中确实有一些进程在后台运行,但是它不会让我终止它们(它说不允许操作),所以也许信号量已经初始化,不会让我重新初始化吗?
还有另一件事。第一个示例将IPC_CREAT | IPC_EXCL | 0666
传递给sem_get
,但是当我这样做时,semget
返回-1。仅通过IPC_CREAT
时才有效。
如果您能让我知道0666
所做的事情,那将是很好的,因为没有示例可以解释。
答案 0 :(得分:2)
问题
*semid = semget(KEY, 1, IPC_CREAT | IPC_EXCL | 0666);
和
int ret = semctl( *semid, 0, SETVAL, value);
几乎可以肯定是由于*semid
所标识的Sys V信号灯已经具有不正确的权限而引起的,这很可能是因为较早的创建遗漏了0666
权限。由于信号灯ID已经存在,因此无法使用设置了IPC_EXCL
的标志将其附加。
假设您正在Linux上运行,the ipcs -s
command将向您显示现有的Sys V信号灯。然后,您可以使用the ipcrm
command删除权限不正确的信号灯并重新开始。
答案 1 :(得分:2)
程序将打印
Unable to set semaphore value: permission denied
。
这是因为,如果您提出的semget()
呼叫实际上创建了一个新的信号量集,它将创建该信号量集,并且没有任何人的访问权限。您可能想要更多类似这样的东西:
*semid = semget(KEY, 1, IPC_CREAT | S_IRUSR | S_IWUSR);
这将指定模式0600;根据需要添加更多权限。 S_
宏通过open()
函数记录。
我应该提到的一件事是确实存在流程 从以前的时间在后台运行 程序,但它不会让我终止它们(它说操作不 允许),因此信号量可能已经初始化,因此不会 让我重新初始化吗?
我看不出任何原因让您呈现的特定程序在后台继续运行,但是它创建的任何信号集都具有内核持久性:它一直存在直到被明确删除为止,直到您的特定程序终止为止。您应该能够使用ipcs
命令来获取当前信号量的列表,并使用ipcrm
命令来删除旧的信号量。这些可能需要root特权。
第一个示例将
IPC_CREAT | IPC_EXCL | 0666
传递给sem_get
, 但是当我这样做时,semget返回-1。只有在IPC_CREAT
已通过。
这又是信号量设置超出程序寿命的问题。当您指定IPC_EXCL
时,如果已存在使用指定键设置的信号量,则显式请求该调用失败(返回-1),因此该调用不会重新创建该信号。省略0666
时包括模式位(IPC_EXCL
)并不无害,但它们仅在创建新的信号量集时才有效。我上面引用的S_IRUSR
和S_IWUSR
常量代表两个特定的模式位,通常,我建议使用常量而不是对模式进行数字编码。
顺便说一句,请注意ftok()
函数是获取键值以标识信号量集的常规方法。