pthread не дает ожидаемый результат - PullRequest
0 голосов
/ 17 апреля 2019

Я пытаюсь реализовать проблемную операционную систему Producer-Consumer, используя семафор и pthread.Но мой результат полностью отличается от ожидаемого.Вот мой код:

    #include<iostream>
    #include<pthread.h>
    #include<fstream>
    #include<unistd.h>
    #include<queue>

    // define queue size
    #define QUEUE_SIZE 5

    // declare and initialize semaphore and read/write counter
    static int semaphore = 1;
    static int counter = 0;

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

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

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

    // function to wait for semaphore
    void wait()
    {
        while(semaphore<=0);
        semaphore--;
    }

    // function to signal the wait function
    void signal()
    {
        semaphore++;
    }

    void *Producer(void *ptr)
    {
        int i=0;
        std::ifstream input("string.txt");
        char temp;
        while(input>>temp)
        {
            wait();
            charQueue.push(temp);
            //std::cout<<"Producer:\nCounter: "<<counter<<" Semaphore: "<<semaphore<<std::endl;
            counter++;
            std::cout<<"Procuder Index: "<<i<<std::endl;
            i++;
            signal();
            sleep(2);
        }
        endOfFile = true;
        pthread_exit(NULL);
    }

    void *Consumer1(void *ptr)
    {
        std::cout<<"Entered consumer 1:"<<std::endl;
        int i = 0;
        while(counter<=0);
        while(!endOfFile)
        {
            while(counter<=0);
            wait();
            //std::cout<<"Consumer1:\nCounter: "<<counter<<" Semaphore: "<<semaphore<<std::endl;
            consumerArray1[i] = charQueue.front();
            charQueue.pop();
            i++;
            counter--;
            std::cout<<"Consumer1 index:"<<i<<" char: "<<consumerArray1[i]<<std::endl;
            signal();
            sleep(2);
        }
        consumerArray1[i] = '\0';
        pthread_exit(NULL);
    }

    void *Consumer2(void *ptr)
    {
        std::cout<<"Entered consumer 2:"<<std::endl;
        int i = 0;
        while(counter<=0);
        while(!endOfFile)
        {
            while(counter<=0);
            wait();
            //std::cout<<"Consumer2:\nCounter: "<<counter<<" Semaphore: "<<semaphore<<std::endl;
            consumerArray2[i] = charQueue.front();
            charQueue.pop();
            i++;
            counter--;
            std::cout<<"Consumer2 index: "<<i<<" char: "<<consumerArray2[i]<<std::endl;
            signal();
            sleep(4);
        }
        consumerArray2[i] = '\0';
        pthread_exit(NULL);
    }

    int main()
    {
        pthread_t thread[3];
        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;
        pthread_exit(NULL);
    }

Проблема в моем коде, который в некоторых прогонах зависает (вероятно, в бесконечном цикле) после того, как весь файл был прочитан.А также обе потребительские функции читают одни и те же слова, хотя я вычитываю их после прочтения.Также часть печати прочитанного элемента массива просто печатает пустой.Почему эти проблемы происходят?Я новичок в потоках (как в кодировании с использованием потоков, я знаю теоретические концепции потоков), поэтому, пожалуйста, помогите мне с этой проблемой.

1 Ответ

2 голосов
/ 17 апреля 2019

Стандарт pthreads запрещает доступ к объекту в одном потоке, в то время как другой поток изменяет или может изменять его.Ваши функции wait и signal нарушают это правило, изменяя semaphoresignal), в то время как поток, вызывающий wait, может обращаться к нему.Вы также делаете это с counter.

Если бы то, что вы делали в signal и wait, было бы законным, вам бы не понадобились signal и wait.Вы можете просто получить доступ к очереди точно так же, как вы напрямую semaphore.Если очередь нуждается в защите (как, я надеюсь, вам это известно), то semaphore тоже нуждается в защите и по той же причине.

Компилятору разрешено оптимизировать этот код:

while(semaphore<=0);

К этому коду:

if (semaphore<=0) { while (1); }

Почему?Потому что он знает, что никакой другой поток не может изменить semaphore, пока этот поток может получить к нему доступ, поскольку это запрещено стандартом.Следовательно, нет смысла читать более одного раза.

Вам необходимо использовать настоящие семпахоры и / или замки.

...