我正在try 用信号量实现生产者和消费者的问题.我想我的逻辑是正确的,但是我的代码并没有像预期的那样工作.

#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(常量字符*名称,int Omark,模式_t模式,无符号整数值);

如果在OFLAG中指定了O_CREAT,则有两个附加参数 必须供应.模式参数指定对 被放在新的信号量上,值 参数指定新信号量的初始值.

注意:我不能使用sem_init,因为最后的代码需要在MacOS上完成.我只是在Linux上用sem_getValue()重新创建它,以了解问题.

在@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

线程继续无限期地等待未正确初始化的mutex信号量.

推荐答案

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

命名信号量由格式为/somename的名称标识;即,最多NAME_MAX-4个以NULL结尾的字符串 (即251个)字符,由一个开始的斜杠组成,后面跟着一个或多个字符,这些字符中没有一个是斜杠.二 通过将相同的名称传递给sem_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支持.其他平台可能有不同的支持位置,但必须支持相同的语义.

需要手动取消信号量链接的明显必然结果是,如果您使用don't,则每次打开具有相同名称的信号量时都会得到相同的信号量.不使用传递给sem_open的值unless,创建信号量.如果具有该名称的信号量已经存在(因为它尚未解除链接),则它只包含前一个或多个运行遗留下来的值.

如果您真的只想在单个进程内使用信号量,而不能使用未命名的信号量(带有sem_init()),那么您可能应该确保名称是唯一的.从PID形成字符串将是一个很好的开始,在退出时取消它的链接也是一个好的开始.

C++相关问答推荐

Malloc(sizeof(char[Length]))是否不正确?

SDL 2.0-从数组渲染纹理

将fget()与strcMP()一起使用不是正确的比较

S将C语言宏定义为自身的目的是什么?(在glibc标题中看到)

为什么双精度d=flt_max+flt_max;在c语言中得到inf的结果

在C中包装两个数组?

将变量或参数打包到 struct /联合中是否会带来意想不到的性能损失?

试图创建一个基本的Word克隆,但遇到了障碍

C语言中的数字指针

不确定如何处理此编译错误

合并对 struct 数组进行排序

*S=0;正在优化中.可能是GCC 13号虫?或者是一些不明确的行为?

Fscanf打印除退出C代码为1的程序外的所有内容

程序对大输入给出错误答案

C语言中的指针和多维数组

C/C++编译器可以在编译过程中通过按引用传递来优化按值传递吗?

使用fread()函数读取txt文件

C语言程序流程解释

C 中类型说明符的顺序重要吗?

定义 int a = 0, b = a++, c = a++;在 C 中定义了行为吗?