Unix信号灯-无法设置初始值

时间:2019-03-19 15:39:17

标签: c++ semaphore

我正在尝试启动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所做的事情,那将是很好的,因为没有示例可以解释。

2 个答案:

答案 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_IRUSRS_IWUSR常量代表两个特定的模式位,通常,我建议使用常量而不是对模式进行数字编码。

顺便说一句,请注意ftok()函数是获取键值以标识信号量集的常规方法。