2017-10-24 4 views
2

Ich habe versucht, Monitor in C mit Semaphor zu implementieren, um Producer Consumer Problem mit begrenzten Puffer zu lösen. Folgendes ist der Code, mit dem ich Monitor implementiert habe.Implementieren von Monitor in C mit Semaphor, führt zu Deadlock

#include<semaphore.h> 

int availableItemCounts; 
int bufferSize; 
int itemShouldBeProducedCount; 
int itemShouldBeConsumedCount; 
int availableItemIndex;//index of last item inserted in buffer. 
char *buffer; 
sem_t mutex; 

typedef struct 
{ 
    sem_t semaphore; 
    int numberOfBlockedThreads; 
} Condition; 

Condition bufferIsFull, bufferIsEmpty; 


int countCV(Condition conditionVariable) 
{ 
    return conditionVariable.numberOfBlockedThreads; 
} 

void waitCV(Condition conditionVariable) 
{ 
    conditionVariable.numberOfBlockedThreads++; 
    sem_wait(&(conditionVariable.semaphore)); 
} 

void signalCV(Condition conditionVariable) 
{ 
    if(countCV(conditionVariable)>0) 
    { 
     sem_post(&(conditionVariable.semaphore)); 
     conditionVariable.numberOfBlockedThreads--; 
    } 
    else 
    { 
     sem_post(&mutex); 
    } 
} 


void monitorInit(int buffSize, int itemSBPC,int itemSBCC) 
{ 
    availableItemCounts=0; 
    availableItemIndex=-1; 
    bufferSize=buffSize; 
    itemShouldBeProducedCount=itemSBPC; 
    itemShouldBeConsumedCount=itemSBCC; 
    char tempBuffer[bufferSize]; 
    buffer=tempBuffer; 
    sem_init(&(bufferIsFull.semaphore), 0, 0); 
    sem_init(&(bufferIsEmpty.semaphore), 0, 0); 
    sem_init(&(mutex), 0, 1); 
    bufferIsEmpty.numberOfBlockedThreads=0; 
    bufferIsFull.numberOfBlockedThreads=0; 
} 

void monitor_Insert(char item) 
{ 
    sem_wait(&mutex); 
    if (itemShouldBeProducedCount>0) 
    { 
     if(availableItemCounts==bufferSize) 
     { 
      sem_post(&mutex); 
      waitCV(bufferIsFull); 
      sem_wait(&mutex); 
     } 
     availableItemIndex++; 
     buffer[availableItemIndex]=item; 
     printf("p:%lu, item: %c, at %d\n", pthread_self(), item, availableItemIndex); 
     itemShouldBeProducedCount--; 
     availableItemCounts++; 
     signalCV(bufferIsEmpty); 
    } 
    else 
    { 
     sem_post(&mutex); 
     pthread_exit(NULL); 
    } 

} 

void monitor_Remove(char item) 
{ 
    sem_wait(&mutex); 
    if (itemShouldBeConsumedCount>0) 
    { 
     if(availableItemCounts==0) 
     { 
      sem_post(&mutex); 
      waitCV(bufferIsEmpty); 
      sem_wait(&mutex); 
     } 
     item=buffer[availableItemIndex]; 
     printf("c:%lu, item: %c, at %d\n", pthread_self(), item, availableItemIndex); 
     availableItemIndex--; 
     itemShouldBeConsumedCount--; 
     availableItemCounts--; 
     signalCV(bufferIsFull); 

    } 
    else 
    { 
     sem_post(&mutex); 
     pthread_exit(NULL); 
    } 
} 

und das ist meine Hauptdatei (Hauptfunktion):

#include<stdio.h> 
#include<pthread.h> 
#include<semaphore.h> 
#include<stdlib.h> 
#include "Monitor.h" 

void *produce(void *index); 
void *consume(void *index); 

int itemShouldBeProducedCount;//total number of items that should be produced. 
int itemShouldBeConsumedCount;//total number of items that should be consumed. 
int bufferSize; 


int main(int argc, char **argv) 
{ 

    int index; 
    int error; 
    int producerCount=atoi(argv[4]); 
    int consumerCount=atoi(argv[6]); 

    itemShouldBeProducedCount=atoi(argv[8]); 
    itemShouldBeConsumedCount=itemShouldBeProducedCount; 
    bufferSize=atoi(argv[2]); 

    monitorInit(bufferSize,itemShouldBeProducedCount,itemShouldBeConsumedCount); 

    sem_init(&(bufferIsFull.semaphore), 0, 0); 
    sem_init(&(bufferIsEmpty.semaphore), 0, 0); 

    printf("Producer Count:%d\n", producerCount); 
    printf("Consumer Count:%d\n", consumerCount); 
    printf("Buffer size Count:%d\n", bufferSize); 
    printf("Items should be produced:%d\n", itemShouldBeProducedCount); 
    printf("Items should be consumed:%d\n", itemShouldBeConsumedCount); 

    monitorInit(bufferSize,itemShouldBeProducedCount,itemShouldBeConsumedCount); 

    pthread_t producerThreads[ producerCount ]; 
    pthread_t consumerThreads[ consumerCount ]; 

    for(index = 0; index < producerCount; index++) 
    { 
     printf("In main: creating producer thread %d\n", index); 
     error = pthread_create(&producerThreads[index], NULL, produce, &index); 

    } 

    for(index = 0; index < consumerCount; index++) 
    { 
     printf("In main: creating consumer thread %d\n", index); 
     error = pthread_create(&consumerThreads[index], NULL, consume, &index); 

    } 


    // wait for each producer thread to complete 
    for(index = 0; index < producerCount; ++index) 
    { 
     // block until thread 'index' completes 
     pthread_join(producerThreads[ index ], NULL); 
     printf("In main: producer thread %d has completed\n", index); 
    } 

    // wait for each consumer thread to complete 
    for(index = 0; index < consumerCount; ++index) 
    { 
     // block until thread 'index' completes 
     pthread_join(consumerThreads[ index ], NULL); 
     printf("In main: consumer thread %d has completed\n", index); 
    } 

    sem_destroy(&(bufferIsFull.semaphore)); 
    sem_destroy(&(bufferIsEmpty.semaphore)); 

    return 0; 
} 

void *produce(void *threaID) 
{ 
    unsigned char item; 
    while(1) 
    { 
     item= (unsigned char) (rand() % 256);//generating an item 
     monitor_Insert(item); 
    } 
    return NULL; 
} 

void *consume(void *threaID) 
{ 
    while(1) 
    { 
     char item; 
     monitor_Remove(item); 

    } 
    return NULL; 
} 

aber leider führt es in einer Sackgasse. Ich habe die Prozesse überprüft und festgestellt, dass alle Produzenten und Konsumenten auf Mutex warten. Was soll ich machen?

+0

Sind Sie sicher, dass weder 'producerCount' noch' consumerCount 'gleich null sind? Sind Sie mit einem Debugger in den Code gegangen? – jwdonahue

+0

Ich bin sicher, dass es 10 Produzenten und 10 Konsumenten erzeugt, und alle von ihnen an irgendeinem Punkt im Programm werden blockiert, während sie darauf warten, Semaphore Mutex freizugeben. – zari

+0

Können Sie jemals einen Semaphor nach Wert übergeben? –

Antwort

0

Fügen Sie sem_post(&mutex); am Ende Ihrer Install- und Remove-Funktionen hinzu. Es gibt einen Weg durch jeden, der zu mehr sem_wait Anrufen als sem_post führt.

EDIT: Sie haben immer noch einen Konstruktionsfehler nach der Behebung dieses Fehlers. Ich empfehle, dass Sie jede der Variablen, die geschützt werden müssen, in eine Struktur platzieren und den Mutex zu dieser hinzufügen, dann erwerben Sie diese Sperre, bevor Sie eine dieser Variablen lesen/schreiben und geben Sie die Sperre frei, sobald Sie fertig sind. Dies ist ein Alles-oder-Nichts-unter-einem-Schloss-Ansatz.

+0

Ich tat es, aber es führte zu inkonsistentem Zugriff auf den Puffer. – zari

+0

Nun, das ist ein anderer Fehler. Sie sind nicht mehr in einer Sackgasse gefangen. – jwdonahue

+0

Was ist also der Sinn der Verwendung eines Monitors, der zu inkonsistentem Zugriff auf gemeinsam genutzte Daten führt, während wir wissen, dass der Monitor ein Mechanismus ist, der solche inkonsistenten Datenzugriffe verhindert? – zari