简体   繁体   English

如何正确同步pthread中的线程?

[英]How to properly synchronous threads in pthreads?

I am implementing a producer-consumer problem using pthreads and semaphore. 我正在使用pthread和信号量实现生产者-消费者问题。 I have 1 Producer and 2 Consumers. 我有1个生产者和2个消费者。 My Producer reads characters one by one from a file and enqueues them into a circular queue. 我的生产者从文件中逐个读取字符,并将它们排入循环队列。 I want the consumers to read from the queue and store into separate arrays. 我希望消费者从队列中读取并存储到单独的数组中。 I want the reading in such a way that the first consumer reads 2 characters and the second consumer reads every 3rd character. 我希望以这样的方式进行读取:第一个使用者读取2个字符,第二个使用者读取每个第3个字符。 I am trying to do this using pthread_cond_wait() but it is not working out. 我正在尝试使用pthread_cond_wait()来执行此操作,但是无法正常工作。 This is my code: 这是我的代码:

#include<iostream>
#include<pthread.h>
#include<fstream>
#include<unistd.h>
#include<semaphore.h>
#include<queue>
#include "circular_queue"

// define queue size
#define QUEUE_SIZE 5

// declare and initialize semaphore and read/write counter
static sem_t mutex,queueEmptyMutex;
//static int counter = 0;

// Queue for saving characters
static Queue charQueue(QUEUE_SIZE);
//static std::queue<char> charQueue;

// indicator for end of file
static bool endOfFile = false;

// save arrays
static char consumerArray1[100];
static char consumerArray2[100];

static pthread_cond_t cond;
static pthread_mutex_t cond_mutex; 
static bool thirdCharToRead = false;

void *Producer(void *ptr)
{
    int i=0;
    std::ifstream input("string.txt");
    char temp;
    while(input>>temp)
    {
        std::cout<<"reached here a"<<std::endl;
        sem_wait(&mutex);
        std::cout<<"reached here b"<<std::endl;
        if(!charQueue.full())
        {
            charQueue.enQueue(temp);
        }
        sem_post(&queueEmptyMutex);
        sem_post(&mutex);

        i++;

        sleep(4);
    }

    endOfFile = true;
    sem_post(&queueEmptyMutex);
    pthread_exit(NULL);
}

void *Consumer1(void *ptr)
{

    int i = 0;
    sem_wait(&queueEmptyMutex);
    bool loopCond = endOfFile;
    while(!loopCond)
    {
        std::cout<<"consumer 1 loop"<<std::endl;
        if(endOfFile)
        {

            loopCond = charQueue.empty();
            std::cout<<loopCond<<std::endl;
            sem_post(&queueEmptyMutex);
        }
       sem_wait(&queueEmptyMutex);


        sem_wait(&mutex);


        if(!charQueue.empty())
        {

            consumerArray1[i] = charQueue.deQueue();
            i++;
            if(i%2==0)
            {
                pthread_mutex_lock(&cond_mutex);
                std::cout<<"Signal cond. i = "<<i<<std::endl;
                thirdCharToRead = true;
                pthread_mutex_unlock(&cond_mutex);
                pthread_cond_signal(&cond);

            }
        }        
        if(charQueue.empty()&&endOfFile)
        {

            sem_post(&mutex);
            sem_post(&queueEmptyMutex);

            break;
        }  
        sem_post(&mutex);

        sleep(2);
        std::cout<<"consumer 1 loop end"<<std::endl;
    }

    consumerArray1[i] = '\0';
    pthread_exit(NULL);

}

void *Consumer2(void *ptr)
{

    int i = 0;
    sem_wait(&queueEmptyMutex);
    bool loopCond = endOfFile;
    while(!loopCond)
    {
        std::cout<<"consumer 2 loop"<<std::endl;
        if(endOfFile)
        {

            loopCond = charQueue.empty();
            std::cout<<loopCond<<std::endl;
            sem_post(&queueEmptyMutex);
        }
        sem_wait(&queueEmptyMutex);


        sem_wait(&mutex);


        if(!charQueue.empty())
        {
            pthread_mutex_lock(&cond_mutex);

            while(!thirdCharToRead)
            {
                std::cout<<"Waiting for condition"<<std::endl;
                pthread_cond_wait(&cond,&cond_mutex);
            }
            std::cout<<"Wait over"<<std::endl;
            thirdCharToRead = false;
            pthread_mutex_unlock(&cond_mutex);

            consumerArray2[i] = charQueue.deQueue();

            i++;
        }  
        if(charQueue.empty()&& endOfFile)
        {
            sem_post(&mutex);
            sem_post(&queueEmptyMutex);
            break;
        }  

        sem_post(&mutex);
        std::cout<<"consumer 2 loop end"<<std::endl;
        sleep(2);

    }

    consumerArray2[i] = '\0';
    pthread_exit(NULL);

}

int main()
{
    pthread_t thread[3];
    sem_init(&mutex,0,1);
    sem_init(&queueEmptyMutex,0,1);
    pthread_mutex_init(&cond_mutex,NULL);
    pthread_cond_init(&cond,NULL);
    pthread_create(&thread[0],NULL,Producer,NULL);
    int rc = pthread_create(&thread[1],NULL,Consumer1,NULL);
    if(rc)
    {
        std::cout<<"Thread not created"<<std::endl;
    }
    pthread_create(&thread[2],NULL,Consumer2,NULL);
    pthread_join(thread[0],NULL);pthread_join(thread[1],NULL);pthread_join(thread[2],NULL);
    std::cout<<"First array: "<<consumerArray1<<std::endl;
    std::cout<<"Second array: "<<consumerArray2<<std::endl;
    sem_destroy(&mutex);
    sem_destroy(&queueEmptyMutex);
    pthread_exit(NULL);
}

The problem I am having is after one read, consumer 2 goes into infinite loop in the while(!thirdCharToRead) . 我遇到的问题是读取一次后,使用者2在while(!thirdCharToRead)进入无限循环。 Is there any better way to implement this? 有没有更好的方法来实现这一目标?

Okay, let's start with this code: 好的,让我们从下面的代码开始:

        std::cout<<"Wait over"<<std::endl;
        pthread_mutex_unlock(&cond_mutex);
        thirdCharToRead = false;

This code says that cond_mutex does not protect thirdCharToRead from concurrent access. 这段代码说cond_mutex不能防止thirdCharToRead并发访问。 Why? 为什么? Because it modifies thirdCharToRead without holding that mutex. 因为它修改了thirdCharToRead而不保留该互斥量。

Now look at this code: 现在看这段代码:

        pthread_mutex_lock(&cond_mutex);

        while(!thirdCharToRead)
        {
            std::cout<<"Waiting for condition"<<std::endl;
            pthread_cond_wait(&cond,&cond_mutex);
        }

Now, the while loop checks thirdCharToRead , so we must hold whatever lock protects thirdCharToRead from concurrent access when we test it. 现在, while循环检查thirdCharToRead ,因此在测试它时,我们必须持有任何保护thirdCharToRead防止并发访问的锁。 But the while loop will loop forever if thirdCharToRead stays locked for the whole loop since no other thread could ever change it. 但是,如果thirdCharToRead在整个循环中保持锁定,则while循环将永远循环,因为没有其他线程可以更改它。 Thus, this code only makes sense if somewhere in the loop we release the lock that protects thirdCharToRead , and the only lock we release in the loop is cond_mutex in the call to pthread_cond_wait . 因此,只有在循环中的某个地方我们释放保护thirdCharToRead的锁,并且在循环中释放的唯一锁是对pthread_cond_wait的调用中的cond_mutex时,此代码才有意义。

So this code only makes sense if cond_mutex protects thirdCharToRead . 因此,仅当cond_mutex保护thirdCharToRead此代码才有意义。

Houston, we have a problem. 休斯顿,我们有一个问题。 One chunk of code says cond_mutex does not protect thirdCharToRead and one chunk of code says cond_mutex does protect thirdCharToRead . cond_mutex代码说cond_mutex不能保护thirdCharToRead而一段代码说cond_mutex可以保护thirdCharToRead

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM