c - "The usage of semaphores is subtly wrong"

标签 c concurrency semaphore producer-consumer

上个学期我参加了 C 语言的操作系统实习,其中第一个项目涉及制作线程包,然后编写一个多生产者-消费者程序来演示功能。然而,在获得评分反馈后,我因“信号量的使用有细微的错误”和“程序假定抢占(例如使用 yield 来更改控制)”而丢分(我们从非抢占线程包开始,后来添加了抢占。请注意,评论和示例相互矛盾。我相信它不会假设任何一个,并且会在两种环境中工作)。

这困扰了我很长时间 - 类(class)工作人员有点不知所措,所以整个学期我都无法问他们这有什么问题。我花了很长时间思考这个问题,但看不到问题所在。如果有人可以看一下并指出错误,或者向我保证实际上没有问题,我将不胜感激。

我认为就线程包函数(微型线程和信号量)而言,语法应该是非常标准的,但如果有任何混淆,请告诉我。

#include <stdio.h>
#include <stdlib.h>
#include "minithread.h"
#include "synch.h"
#define BUFFER_SIZE 16
#define MAXCOUNT 100

int buffer[BUFFER_SIZE];
int size, head, tail;
int count = 1;
int out = 0;
int toadd = 0;
int toremove = 0;

semaphore_t empty;
semaphore_t full;
semaphore_t count_lock; // Semaphore to keep a lock on the 
                        // global variables for maintaining the counts


/* Method to handle the working of a student 
    * The ID of a student is the corresponding minithread_id */
int student(int total_burgers) {
    int n, i;
    semaphore_P(count_lock);
    while ((out+toremove) < arg) {
        n = genintrand(BUFFER_SIZE);
        n = (n <= total_burgers - (out + toremove)) ? n : total_burgers - (out + toremove);
        printf("Student %d wants to get %d burgers ...\n", minithread_id(), n);
        toremove += n;
        semaphore_V(count_lock);
        for (i=0; i<n; i++) {
            semaphore_P(empty);
            out = buffer[tail];
            printf("Student %d is taking burger %d.\n", minithread_id(), out);
            tail = (tail + 1) % BUFFER_SIZE;
            size--;
            toremove--;
            semaphore_V(full);
        }
        semaphore_P(count_lock);
    }
    semaphore_V(count_lock);
    printf("Student %d is done.\n", minithread_id());
    return 0;
}

/* Method to handle the working of a cook 
    * The ID of a cook is the corresponding minithread_id */
int cook(int total_burgers) {
    int n, i;
    printf("Creating Cook %d\n",minithread_id());
    semaphore_P(count_lock);
    while ((count+toadd) <= arg) {
        n = genintrand(BUFFER_SIZE);
        n = (n <= total_burgers - (count + toadd) + 1) ? n : total_burgers - (count + toadd) + 1;
        printf("Cook %d wants to put %d burgers into the burger stack ...\n", minithread_id(),n);
        toadd += n;
        semaphore_V(count_lock);
        for (i=0; i<n; i++) {
            semaphore_P(full);
            printf("Cook %d is putting burger %d into the burger stack.\n", minithread_id(), count);
            buffer[head] = count++;
            head = (head + 1) % BUFFER_SIZE;
            size++;
            toadd--;
            semaphore_V(empty);
        }
        semaphore_P(count_lock);
    }
    semaphore_V(count_lock);
    printf("Cook %d is done.\n", minithread_id());
    return 0;
}

/* Method to create our multiple producers and consumers
    * and start their respective threads by fork */
void starter(int* c){
    int i;
    for (i=0;i<c[2];i++){
        minithread_fork(cook, c[0]);
    }
    for (i=0;i<c[1];i++){
        minithread_fork(student, c[0]);
    }
}


/* The arguments are passed as command line parameters
    * argv[1] is the no of students
    * argv[2] is the no of cooks */
void main(int argc, char *argv[]) {
    int pass_args[3];
    pass_args[0] = MAXCOUNT;
    pass_args[1] = atoi(argv[1]);
    pass_args[2] = atoi(argv[2]);

    size = head = tail = 0;
    empty = semaphore_create();
    semaphore_initialize(empty, 0);
    full = semaphore_create();
    semaphore_initialize(full, BUFFER_SIZE);
    count_lock = semaphore_create();
    semaphore_initialize(count_lock, 1);

    minithread_system_initialize(starter, pass_args);
}

最佳答案

在最内层循环中,您的信号量不会保护缓冲区、头部等。一个线程获取信号量“空”,另一个线程获取信号量“满”,同时没有其他信号量被持有。这似乎保证了最终的腐败。

关于c - "The usage of semaphores is subtly wrong",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4514778/

相关文章:

c - C 中的命名信号量在信号处理程序调用后不会被删除

c - 如何理解变量赋值背后的逻辑?

c - 构建时自动创建目录

java - 使用ExecutorService确定性地将任务分配给线程

Python:如何在一瞬间进行多个 HTTP POST 查询?

linux - Linux 中的并发 : Alternate access of two threads in critical zone

c - y -= m < 3 是什么意思?

c - 重新采样声音样本,我使用什么过滤器?

java - 暂停/恢复线程中的任意计算

c++ - 了解 posix 进程间信号量