制片人,消费者和我可爱的僵局

时间:2014-03-02 00:07:18

标签: c++ multithreading c++11 pthreads

我正在处理Producer Consumer(多线程)问题,我遇到了死锁。我的问题是如何?

我有多个生产者创建n个产品,并将它们放在全局队列中。如果队列中没有空间,则生产者必须等待。

我的消费者正在使用First Come First Serve访问队列。如果队列中没有任何内容,则消费者必须等待。消费者将使用产品的PART,并且只有在完全消耗产品时才会从队列中删除产品。当没有更多的产品需要消费时,消费者将停止消费。

当第一个项目被消耗时,我得到了死锁。我正在使用互斥锁来锁定队列,2个条件变量用于在项目被添加或移除到队列时发出信号,以及信号量用于跟踪正在消耗的项目。

知道为什么它可能会陷入僵局吗?

输入:2(生产者)3(消费者)5(生产项目)2(队列大小)0(N / A)50(量子)1(种子)

制片:

#include <pthread.h>
#include <semaphore.h>
#include "producerConsumer.h"
#include <iostream>
#include <sys/time.h>

void* producer(void* args)
{
    tProducer producer = *((tProducer*) args);
    tProduct products[producer.products];
    unsigned int queueMax = producer.queueMax;
    timeval time;
    std::string output;

    for(int i = 0; i < producer.products; i++)
    {
        //Create item
        products[i].productId = i;
        products[i].life = producer.lifeOfProduct;
        gettimeofday(&time, NULL);
        products[i].timestamp = time.tv_sec;

        //Lock and add to queue
        pthread_mutex_lock(&queueLock);

            //Queue is full and must wait
            if(queue.size() >= queueMax)
            {
                output = "Producer: " + std::to_string(producer.id) + " is waiting\n";
                std::cout << output;
                pthread_cond_wait(&removeSignal, &queueLock);
            }

            //Debug message
            output = "Producer: " + std::to_string(producer.id) + " is producing.\n";
            std::cout << output;

            //Add item to queue and signal
            queue.push(products[i]);
            pthread_cond_signal(&addSignal);
        pthread_mutex_unlock(&queueLock);
        //pthread_cond_signal(&addSignal);

        //Debug message
        output = "Producer: " + std::to_string(producer.id) + " just produced.\n";
        std::cout << output;
    }
    pthread_exit(NULL);
}

消费者:

#include <pthread.h>
#include <semaphore.h>
#include "producerConsumer.h"
#include <iostream>
void* consumer(void* args)
{
    tConsumer consumer = *((tConsumer*) args);
    int id = consumer.id;
    int quantum = consumer.quantum;
    std::string output;

    while(true)
    {
        //Exit when nothing else is being created
        if(sem_trywait(&totalProductsLeft) < 0)
        {
            break;
        }

        //Subtract life from product, and remove from queue if done
        pthread_mutex_lock(&queueLock);

            //Wait until item is in queue
            if(queue.size() <= 0)
            {
                //Debug message
                output = "Consumer: " + std::to_string(id) + " is waiting.\n";
                std::cout << output;
                pthread_cond_wait(&addSignal, &queueLock);
            }

            //Debug message
            output = "Consumer: " + std::to_string(id) + " is ready.\n";
            std::cout << output;

            tProduct& product = queue.front();
            product.life -= quantum;

            //Item is done being consumed
            if(product.life <= 0)
            {
                //Debug message
                output = "Product: " + std::to_string(product.productId) + " is dead.\n";
                std::cout << output;

                //Remove a spot
                queue.pop();
                pthread_cond_signal(&removeSignal);
                sem_wait(&totalProductsLeft);
            }
            else
            {
                //Debug message
                output = "Product: " + std::to_string(product.life) + "hp is not done.\n";
                std::cout << output;
            }

        pthread_mutex_unlock(&queueLock);
    }

    //May need to broadcast
    pthread_exit(NULL);
}

Main(只是为了展示我如何初始化所有内容):

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <pthread.h>
#include <semaphore.h>
#include "producerConsumer.h"

std::queue<tProduct> queue;
pthread_cond_t addSignal;
pthread_cond_t removeSignal;
sem_t totalProductsLeft;
pthread_mutex_t queueLock;

int main(int argc, char** argv)
{
    //Handle input
    const int NUM_INPUTS = 8;
    int numberProducers;
    int numberConsumers;
    int numberOfProducts;
    int queueSize;
    int scheduleType;
    int quantum;
    int seed;

    //Error check for input
    if(argc != NUM_INPUTS)
    {
        std::cout << "Invalid number of arguments.\n";
        return -1;
    }

    //Grab arguments
    numberProducers = atoi(argv[1]);
    numberConsumers = atoi(argv[2]);
    numberOfProducts = atoi(argv[3]);
    queueSize = atoi(argv[4]);
    scheduleType = atoi(argv[5]);
    quantum = atoi(argv[6]);
    seed = atoi(argv[7]);

    //Get rid of warnings for now
    std::cout << numberOfProducts << std::endl;
    std::cout << queueSize << std::endl;
    std::cout << quantum << std::endl;
    std::cout << seed << std::endl;
    std::cout << scheduleType << std::endl;

    //Create threads
    pthread_t producerThreads[numberProducers];
    pthread_t consumerThreads[numberConsumers];
    tProducer producerArgs[numberProducers];
    tConsumer consumerArgs[numberConsumers];

    //Initialize global
    pthread_mutex_init(&queueLock, NULL);
    pthread_cond_init(&addSignal, NULL);
    pthread_cond_init(&removeSignal, NULL);
    std::cout << "Total Items: " << (numberProducers * numberOfProducts) << std::endl;
    sem_init(&totalProductsLeft, 0, numberProducers * numberOfProducts);

    //Start threads
    srand(seed);
    for(int i = 0; i < numberProducers; i++)
    {
        producerArgs[i].id = i;
        producerArgs[i].products = numberOfProducts;
        producerArgs[i].lifeOfProduct = rand() % 1024;
        producerArgs[i].queueMax = queueSize;
        pthread_create(&(producerThreads[i]), 0, producer, &producerArgs[i]);
    }

    for(int i = 0; i < numberConsumers; i++)
    {
        consumerArgs[i].id = i;
        consumerArgs[i].quantum = quantum;
        pthread_create(&(consumerThreads[i]), 0, consumer, &consumerArgs[i]);
    }

    //Wait for threads to end
    for(int i = 0; i < numberProducers; i++)
    {
        pthread_join(producerThreads[i], NULL);
    }

    for(int i = 0; i < numberConsumers; i++)
    {
        pthread_join(consumerThreads[i], NULL);
    }

    return 0;
}

1 个答案:

答案 0 :(得分:1)

我最终搞清楚了。在我的消费者中,sem_trywait在没有消耗物品时递减。然后我的消费者中的sem_wait被阻止,因为没有剩下的项目。