使用信号量在C中实现Monitor会导致死锁

时间:2017-10-24 03:29:27

标签: c semaphore monitor

我尝试使用信号量在C中实现monitor,以便用有界缓冲区解决生产者消费者问题。 以下是我用来实现监视器的代码。

#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);
    }
}

这是我的主文件(主要功能):

#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;
}

但不幸的是它会导致死锁。我检查了进程,发现所有生产者和消费者都在等待互斥锁。我该怎么办?

1 个答案:

答案 0 :(得分:0)

sem_post(&mutex);添加到您的instert的末尾并删除功能。每个通道都有一条途径可以导致sem_wait次呼叫比sem_post更多。

编辑:修复此错误后仍然存在设计缺陷。我建议您将每个必须保护的变量放入结构中并将互斥锁添加到该结构中,然后在读取/写入任何这些变量之前获取该锁定,并在完成后立即释放锁定。这是一种锁定方式下的全有或全无。