【问题标题】:C Producer Consumer using semaphoresC 生产者消费者使用信号量
【发布时间】:2017-05-10 15:07:34
【问题描述】:

为什么,对于我的代码输出的前几次迭代,消费者消费了两次 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);
    }

【问题讨论】:

  • 请提供minimal reproducible example。您当前的示例不包括main() 函数,也不包括up() 和down() 的实现(考虑到typedef 的semaphore,这非常可疑)。

标签: c mutex semaphore


【解决方案1】:

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

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

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

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

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

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

  • 在同一组中创建 3 个信号量并将它们分配为 空信号量、满信号量和互斥信号量。参考 在调用semop()、semctl 等时,通过它的号码显示相关信号量。

修复第 2 项:

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

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

semctl(semid_full, 0, SETVAL, arg);

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-05
    • 2016-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-22
    相关资源
    最近更新 更多