Многопоточное программирование на c языке: производитель-потребитель. Ошибка мьютекса? - PullRequest
0 голосов
/ 03 мая 2020

Мне нужно создать M потоков производителей и N потоков последовательностей на языке c. Программа должна сделать K вставок и K извлечений из очереди. Проблема заключается в том, что когда я выполняю программу, несколько потоков потребителей получают доступ к одному и тому же элементу очереди (и они его извлекают). Таким образом, счетчик "cont" приводит к тому же результату в некоторых извлечениях, и я не понимаю почему, потому что мьютекс и условная переменная, я думаю, правильные.

typedef struct List {
        int msg;
        struct List* next;
}List;

typedef struct QueueList {
        List* list;
        List* last;
        int cont;
}Queue;

static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static int K;
static int N;
static int M;
static Queue q;
static void* producer();
static void* consumer();

void push(int num) {
        List* l = (List*) malloc(sizeof(List));
        l->msg = num;
        l->next = NULL;
        if(q.list == NULL)
                q.last = q.list = l;
        else {
                q.last->next = l;
                q.last = q.last->next;
        }
        return;
}

void pop() {
        List* l;
        if(q.list == NULL) {
                printf("Head is NULL\n");
                return;
        }
        l = q.list;
        q.list = q.list->next;
        free(l);
        q.cont--;
        return;
}

static void* producer() {
        for(int i = 0; i < K/M; ++i) {
                Pthread_mutex_lock(mtx);
                push(i);
                printf("Producer(insert): %d\n", q.last->msg);
                Pthread_cond_signal(cond);
                Pthread_mutex_unlock(mtx);
        }
        pthread_exit(NULL);
}

static void* consumer() {
        while(1) {
                Pthread_mutex_lock(mtx);
                while(q.list == NULL && q.cont > 0)
                        Pthread_cond_wait(cond, mtx);
                if(q.cont == 0)
                        break;
                printf("Consumer(extract): %d  Counter: %d\n", q.list->msg, q.cont);
                pop();
                Pthread_mutex_unlock(mtx);
        }
        Pthread_mutex_unlock(mtx);
        pthread_exit(NULL);
}

//there are the Pthread function too but they are correct

int main(int argc, char* argv[])
{
    if(argc != 4) {
        fprintf(stderr, "Usage: %s N M K\n", argv[0]);
        exit(1);
    }
    N = atoi(argv[1]);
    M = atoi(argv[2]);
    K = atoi(argv[3]);

    q.list = q.last = NULL;
    q.cont = K - ((K%M)*M);

    pthread_t *p, *c;
    p = (pthread_t*) malloc(sizeof(pthread_t)*M);
    c = (pthread_t*) malloc(sizeof(pthread_t)*N);
    int err;
    for(int i = 0; i < M; ++i)
        if((err = pthread_create(&p[i], NULL, &producer, NULL)) != 0) {
            errno = err;
            perror("Creating thread");
            pthread_exit(&errno);
        }
    for(int i = 0; i < N; ++i)
        if((err = pthread_create(&c[i], NULL, &consumer, NULL)) != 0) {
            errno = err;
            perror("Creating thread");
            pthread_exit(&errno);
        }

    for(int i = 0; i < M; ++i)
        Pthread_join(p[i]);
    for(int i = 0; i < N; ++i)
        Pthread_join(c[i]);

    List* l;
    while(q.list != NULL) {
        l = q.list;
        q.list = q.list->next;
        free(l);
    }
    free(p);
    free(c);
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...