Должны ли мы использовать мьютекс с семафором для правильной синхронизации и предотвращения состояния гонки? - PullRequest
0 голосов
/ 01 сентября 2018

Я пытаюсь увидеть, что состояние гонки происходит в проблеме потребитель-производитель, поэтому я сделал несколько производителей и нескольких потребителей.

Из того, что я знаю, мне нужно предоставить мьютекс семафором: Mutex для условий гонки, потому что несколько производителей могут получить доступ к буферу одновременно. тогда данные могут быть повреждены.

И семафор для обеспечения сигнализации между производителями и потребителями

Проблема здесь в том, что синхронизация происходит правильно, когда я не использую мьютекс (я использую только семафор). мое понимание верно или что-то не так в коде ниже:

#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>
#include <stdlib.h>
#include <unistd.h>

int buffer;
int loops = 0;

sem_t empty;
sem_t full;
sem_t mutex; //Adding MUTEX

void put(int value) {
    buffer = value;       
}

int get() {
    int b = buffer;      
    return b;
}



void *producer(void *arg) {
    int i;
    for (i = 0; i < loops; i++) {
        sem_wait(&empty);

        //sem_wait(&mutex);
        put(i);
        //printf("Data Set from %s, Data=%d\n", (char*) arg, i);
        //sem_post(&mutex);

        sem_post(&full);
    }
}

void *consumer(void *arg) {
    int i;
    for (i = 0; i < loops; i++) {
        sem_wait(&full);

        //sem_wait(&mutex);
        int b = get();
        //printf("Data recieved from %s, %d\n", (char*) arg, b);
        printf("%d\n", b);
        //sem_post(&mutex);

        sem_post(&empty);

    }
}

int main(int argc, char *argv[])
{
    if(argc < 2 ){
        printf("Needs 2nd arg for loop count variable.\n");
        return 1;
    }

    loops = atoi(argv[1]);

    sem_init(&empty, 0, 1); 
    sem_init(&full, 0, 0);    
    sem_init(&mutex, 0, 1);

    pthread_t pThreads[3];
    pthread_t cThreads[3];


    pthread_create(&cThreads[0], 0, consumer, (void*)"Consumer1");
    pthread_create(&cThreads[1], 0, consumer, (void*)"Consumer2");
    pthread_create(&cThreads[2], 0, consumer, (void*)"Consumer3");

    //Passing the name of the thread as paramter, Ignore attr
    pthread_create(&pThreads[0], 0, producer, (void*)"Producer1");
    pthread_create(&pThreads[1], 0, producer, (void*)"Producer2");
    pthread_create(&pThreads[2], 0, producer, (void*)"Producer3");


    pthread_join(pThreads[0], NULL);
    pthread_join(pThreads[1], NULL);
    pthread_join(pThreads[2], NULL);

    pthread_join(cThreads[0], NULL);
    pthread_join(cThreads[1], NULL);
    pthread_join(cThreads[2], NULL);

    return 0;
}

1 Ответ

0 голосов
/ 05 сентября 2018

Мне кажется, я понял проблему. Вот что происходит

При инициализации семафоров вы устанавливаете количество потоков empty в 1, а full - 0

sem_init(&empty, 0, 1); 
sem_init(&full, 0, 0);    
sem_init(&mutex, 0, 1);

Это означает, что есть только одно «пространство» для потока, чтобы попасть в критическую область. Другими словами, ваша программа делает

produce (empty is now 0, full has 1)
consume (full is now 0, empty has 0)
produce (empty is now 0, full has 1)
...

Это как если бы у вас был токен (или, если хотите, мьютекс), и вы передавали этот токен между потребителями и производителями. В этом-то и состоит проблема потребителей и производителей, только в большинстве случаев мы беспокоимся о том, чтобы несколько потребителей и производителей работали одновременно (что означает, что у вас более одного токена). Здесь, поскольку у вас есть только один токен, у вас есть то, что будет делать один мьютекс.

Надеюсь, это помогло:)

...