提问人:Ku-hello 提问时间:10/9/2023 最后编辑:Ku-hello 更新时间:10/9/2023 访问量:87
信号量未使用 sem_open 正确初始化
Semaphore not initialised properly with sem_open
问:
我正在尝试用信号量实现生产者和消费者问题。我想我的逻辑是正确的,但我的代码没有按预期工作。
#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
线程无限期地等待互斥信号量,该信号量再次未正确初始化。
答:
从我的本地手册页来看,您的手册可能有所不同:sem_overview
命名信号量由以下形式的名称标识;也就是说,最多(即 251 个)字符的以 null 结尾的字符串,由初始斜杠组成,后跟一个或多个字符,其中没有一个是斜杠。二 进程可以通过将相同的名称传递给 来对同名信号量进行操作。
/somename
NAME_MAX-4
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
需要手动取消链接信号量的明显推论是,如果不这样做,每次打开同名信号量时都会得到相同的信号量。除非创建信号量,否则不会使用传递给的值。如果具有该名称的信号量已经存在(因为它尚未取消链接),则它只包含上一次或多次运行中剩余的任何值。sem_open
如果您真的只想在单个进程中使用信号量,而不能使用未命名的信号量(使用 ),您可能应该确保该名称是唯一的。从 PID 形成一个字符串将是一个好的开始,就像在退出时取消链接一样。sem_init()
评论