gpt4 book ai didi

使用信号量的 C 生产者消费者

转载 作者:行者123 更新时间:2023-11-30 19:09:02 25 4
gpt4 key购买 nike

为什么在我的代码输出的前几次迭代中显示消费者消耗了 0 两次,而它应该消耗生产的前两项?

Consumer consumes 0
Producer produces 17
Producer produces 17
Consumer consumes 0
Producer produces 10
Producer produces 12
Consumer consumes 10
Producer produces 11
Producer produces 43
Consumer consumes 12
Producer produces 33
Producer produces 39
Consumer consumes 11

这是我的一些用于显示的代码

#define N 10

typedef int semaphore;
semaphore mutex, full, empty;

int first=0,last=0, semArray[N];

可以使用全局变量吗?

int produce_item(){
int item = rand()%50 +1;
printf("Producer produces %d\n",item);
sleep(1);
return item;
}

void consume_item(int item){
printf("Consumer consumes %d\n",item);
sleep(2);
}

int remove_item(){
int temp = semArray[first];
first = first +1;
return temp;
}

void insert_item(int item){
semArray[last] = item;
last++;
}

这是信号量的生产者和消费者函数

void* consumer(void* arg) {
int item, i=0;
while(1){
down(full);
down(mutex);
item = remove_item();
up(mutex);
up(empty);
consume_item(item);
}
return 0;
}

void* producer(void* arg) {
int item, i=0;
while(1){
item=produce_item();
down(empty);
down(mutex);
insert_item(item);
up(mutex);
up(full);
}
return 0;
}

void down(semaphore s){
setSemaphore(s,0,-1);
}

void up(semaphore s){
setSemaphore(s,0,1);
}


int setSemaphore(int semID, int semNum, int semOp){
struct sembuf Buf;
Buf.sem_num = semNum;
Buf.sem_op = semOp;
Buf.sem_flg = 0;
return semop(semID,&Buf,1);
}
main() {
int i;
pthread_t threads[2];
srand(time(NULL));
int semid_full, semid_empty, semid_mutex;

key_t key;
key = ftok("task2.c", 'J');

//initialize and create each semaphore set
semid_empty = semget(key, 1, 0600|IPC_CREAT);
arg.val = N;
semctl(semid_empty, 0, SETVAL, arg);
semid_full = semget(key, 1, 0600|IPC_CREAT);
arg.val = 0;
semctl(semid_empty, 0, SETVAL, arg);
semid_mutex = semget(key, 1, 0600|IPC_CREAT);
arg.val = 1;
semctl(semid_mutex, 0, SETVAL, arg);

pthread_create(&threads[0],NULL,consumer,NULL);
pthread_create(&threads[1],NULL,producer,NULL);
//remove
semctl(semid_empty, 0 , IPC_RMID, arg);
semctl(semid_full, 0, IPC_RMID,arg);
semctl(semid_mutex, 0 , IPC_RMID, arg);
for(i=0; i<2; i++) {
pthread_join(threads[i],NULL);
}

最佳答案

在希望这段代码能够正常工作之前,有一些明显的问题需要修复:

  1. semid_emptysemid_emptysemid_empty相同信号量集,因此所有 semop() 操作都在同一个信号量上进行。
  2. 代码立即删除信号量集创建生产者和消费者线程之后。所有后续在这些线程中调用 semop() 失败。
  3. 当尝试将 semid_full 初始化为 0 时,代码错误地使用 semid_empty 作为信号量 ID。

有几种方法可以修复第 1 项:

  • 对每个信号量集使用不同的 key ,或者,因为信号量仅在同一进程中使用,您可以简单地使用 IPC_PRIVATE作为关键,例如

    semid_empty = semget(IPC_PRIVATE, 1, 0600|IPC_CREAT);

    这将确保每个信号量集都是唯一的。

  • 在同一组中创建 3 个信号量,并为它们分配角色空信号量、满信号量和互斥信号量。引用通过调用 semop()semctl 等中的编号来识别相关信号量。

要修复第 2 项:

  • 不要删除信号量。信号量将根据需要在程序执行之间重新创建或重用。只要每次都正确初始化,一切都会很好,或者
  • 组织在进程退出时删除信号量。你可能会使用信号或任何其他可用的方法。

第 3 项可能只是一个拼写错误,请使用以下方法修复它:

semctl(semid_full, 0, SETVAL, arg);

最后,这非常重要,在您的代码中添加错误检查和日志记录;这些问题中的大多数都会立即显现出来,尤其是 setSemaphore() 中的 semop() 失败。这会让你自己发现问题。

我不确定修复上述问题是否可以解决所有代码问题,或者您的算法是否正确,但这是一个开始,然后您可以尝试添加调试日志记录和错误检查来解决任何其他潜在问题。

关于使用信号量的 C 生产者消费者,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43896361/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com