信号量未使用 sem_open 正确初始化

Semaphore not initialised properly with sem_open

提问人:Ku-hello 提问时间:10/9/2023 最后编辑:Ku-hello 更新时间:10/9/2023 访问量:87

问:

我正在尝试用信号量实现生产者和消费者问题。我想我的逻辑是正确的,但我的代码没有按预期工作。

#include <stdio.h> 
#include <pthread.h> 
#include <semaphore.h> 
#include <unistd.h> 
#include <fcntl.h>
#include <sys/stat.h>
#include <stdlib.h>
 
#define BUFFER_SIZE 10
 
int arr[BUFFER_SIZE];
int position;
 
sem_t *mutex, *empty, *filled;
 
void* producer(void* args){
    printf("Prod starting\n");
    int a,b;
    sem_getvalue(empty, &a);
    sem_getvalue(mutex, &b);

    printf("empty : %d mutex : %d\n", a, b);

    do{
        sem_wait(empty);
        sem_wait(mutex);
         

        int new = rand()%2000;
        printf("Adding %d to buffer\n", new);
        arr[position] = new;
        position++;

        sem_post(mutex);
        sem_post(filled);
    }while(1);
 
}
 
void* consumer(void* arg){printf("Consumer starting\n");
    do{
        sem_wait(filled);
        sem_wait(mutex);
         
        position--;
        printf("Consuming %d from buffer", arr[position]);
        arr[position] = 0; 

        sem_post(mutex);
        sem_post(empty);
    }while(1);
}
 
 
int main() 
{ 
    mutex = sem_open("mutex", O_CREAT, 0644, 1);
    empty = sem_open("empty", O_CREAT, 0644, BUFFER_SIZE);
    filled = sem_open("filled", O_CREAT, 0644, 0);
    pthread_t prod, cons;

    int a, b,c;
    sem_getvalue(empty, &a);
    sem_getvalue(filled, &b);
    sem_getvalue(mutex, &c);
    printf("empty:%d filled:%d mutex:%d\n", a,b,c);

    //printf("Producer = %ld  Consumer = %ld\n", prod, cons);
     
    pthread_create(&prod,NULL,producer,NULL); 
    pthread_create(&cons,NULL,consumer,NULL); 
     
    pthread_join(prod,NULL); 
    pthread_join(cons,NULL); 
     
    sem_close(mutex);
    sem_unlink("mutex");
    sem_close(empty);
    sem_unlink("empty");
    sem_close(filled);
    sem_unlink("filled");
    return 0; 
} 

信号量未正确初始化,从以下输出中可以看出:

empty:0 filled:0 mutex:0
Prod starting
empty : 0 mutex : 0
Consumer starting

我不明白为什么信号量没有正确初始化。在手册页中:

sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);

如果在 oflag 中指定了 O_CREAT,则另外两个参数 必须提供。mode 参数指定以下权限 放置在新的信号量上,值 参数指定新信号量的初始值。

注意:我不能使用 sem_init,因为最终代码需要在 Macos 上完成。我只是使用 sem_getvalue() 在 linux 上重新创建它以了解问题所在。

在@pilcrow的建议下,我把问题重现为:

#include <stdio.h> 
#include <pthread.h> 
#include <semaphore.h> 

sem_t *mutex;

void* thread(void* arg){
    printf("Entered thread\n");
    sem_wait(mutex);
    printf("Hello\n");
    sem_post(mutex);
    pthread_exit(NULL);
}

int main() 
{ 
    mutex = sem_open("mutex", O_CREAT, 0644, 1);

    if(mutex == SEM_FAILED){
        printf("Failed to create semaphore\n");
        return 1;
    }
    
    pthread_t id;
    pthread_create(&id,NULL,thread,NULL); 
    pthread_join(id,NULL); 
    return 0; 
}

输出:

Entered thread

线程无限期地等待互斥信号量,该信号量再次未正确初始化。

C pthreads 信号量

评论

1赞 n. m. could be an AI 10/9/2023
始终检查所有内容的返回值。
0赞 Ku-hello 10/9/2023
sem_open() 工作正常。我通过将返回值与SEM_FAILED进行比较进行了检查,它似乎可以正常工作,没有来自sem_open的错误。
0赞 n. m. could be an AI 10/9/2023
尝试指定O_EXCL。
0赞 pilcrow 10/9/2023
你能把它简化成一个简明扼要的例子吗?既然您在初始化新打开的信号量时遇到了麻烦,您能否删除两个信号量,即生产者和消费者?
0赞 Ku-hello 10/9/2023
@pilcrow 正如你所说,我做了一个类似的场景,但它仍然不起作用。我更新了问题。

答:

2赞 Useless 10/9/2023 #1

从我的本地手册页来看,您的手册可能有所不同:sem_overview

命名信号量由以下形式的名称标识;也就是说,最多(即 251 个)字符的以 null 结尾的字符串,由初始斜杠组成,后跟一个或多个字符,其中没有一个是斜杠。二 进程可以通过将相同的名称传递给 来对同名信号量进行操作。/somenameNAME_MAX-4sem_open(3)

该函数创建一个新的命名信号量或打开一个现有的命名信号量。在信号量被 打开后,即可使用和进行操作。当一个进程使用完信号量后,它可以 用于关闭信号量。当所有进程都使用完信号量后,可以从 系统使用 .sem_open(3)sem_post(3)sem_wait(3)sem_close(3)sem_unlink(3)

事实上,多个进程可以打开同一个信号量,这意味着它必须存在于进程范围之外的某个地方。

它需要手动取消链接的事实表明,即使打开它的每个进程都调用了它,它也会继续存在(否则,当引用计数变为零时,它可能会被销毁)。sem_close()

在 linux 上运行测试进程表明信号量由文件支持。其他平台可能具有不同的支持位置,但必须支持相同的语义。strace/dev/shm/sem/mutex

需要手动取消链接信号量的明显推论是,如果不这样做,每次打开同名信号量时都会得到相同的信号量。除非创建信号量,否则不会使用传递给的值。如果具有该名称的信号量已经存在(因为它尚未取消链接),则它只包含上一次或多次运行中剩余的任何值。sem_open

如果您真的只想在单个进程中使用信号量,而不能使用未命名的信号量(使用 ),您可能应该确保该名称是唯一的。从 PID 形成一个字符串将是一个好的开始,就像在退出时取消链接一样。sem_init()

评论

0赞 Ku-hello 10/9/2023
这也解释了我最初的问题。当我第一次运行代码时,生产者-消费者问题工作正常。在我做了一些清理并再次运行它进行确认后,它开始一次又一次地失败。非常感谢伙计。最后的好建议太;)
0赞 Ku-hello 10/9/2023
此外,关于命名信号量的这种行为的材料太少了,直到现在我才看到这一点。