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

Unix Semaphore - unable to set initial value

我正在尝试启动一个 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

我应该提到的一件事是,我以前有 运行 程序的后台似乎确实有 运行ning 进程,但它不会让我终止它们(它说不允许操作),所以也许信号量已经初始化并且它不会让我重新初始化它?

还有一件事。第一个示例将 IPC_CREAT | IPC_EXCL | 0666 传递给 sem_get,但是当我这样做时 semget returns -1。它仅在仅传递 IPC_CREAT 时有效。

如果您能让我知道 0666 的作用,那就太好了,因为 none 的示例对此进行了解释。

的问题
*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 will show you the existing Sys V semaphores. You can then use the ipcrm command 删除权限不正确的信号量并重新开始。

The program prints Unable to set semaphore value: permission denied.

那是因为如果您提出的 semget() 调用实际上创建了一个新的信号量集,它创建它时没有任何人的访问权限。你可能想要更多这样的东西:

*semid = semget(KEY, 1, IPC_CREAT | S_IRUSR | S_IWUSR);

那将分配模式0600;根据需要添加更多权限。 S_ 宏与 open() 函数一起记录。

One thing I should mention is that there does seem to be processes running in the background from previous times that I have run the program, but it won't let me terminate them (it says operation not permitted), so maybe the semaphore is already initialized and it won't let me reinitialize it?

我看不出您提供的特定程序会在后台继续 运行 的任何原因,但是它创建的任何信号量集都具有内核持久性:它一直存在直到被明确删除,这将超过您的时间特定程序的终止。您应该能够使用 ipcs 命令获取当前信号量列表,并使用 ipcrm 命令删除旧信号量。这些可能需要 root 权限。

The first example passes IPC_CREAT | IPC_EXCL | 0666 to sem_get, but when I do this semget returns -1. It only works if just IPC_CREAT is passed.

这又是您的信号量集比程序长寿的问题。当您指定 IPC_EXCL 时,如果具有指定键的信号量集已经存在,则您明确请求调用失败(返回 -1),因此调用不会重新创建。在省略 IPC_EXCL 时包含模式位 (0666) 应该没有害处,但它们仅在创建新的信号量集时才有效。我在上面引用的 S_IRUSRS_IWUSR 常量表示两个特定的模式位,通常我建议使用常量来对模式进行数字编码。

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