Проблема Readers-Writers с pthreads, приводящая только к 1 читателю - PullRequest
1 голос
/ 19 апреля 2019

Моя задача - найти решение проблемы читателей-писателей с помощью posix pthreads. Я порождаю 3 читателей и 1 писатель.

Спецификация задачи просит добавлять значения в очередь 2 за раз (писатели). Считыватели снимают по очереди по очереди (когда в очереди есть значение). Очередь проверена и работает.

Проблема, с которой я столкнулся, заключается в том, что при запуске программы получается, что только 1 поток чтения читает большую часть времени . Иногда повторное выполнение приводит к тому, что все 3 читателя используются. Но в большинстве случаев используется только 1 читатель. Я не уверен, почему это странное поведение происходит.

Заранее спасибо.

Expected (Sometimes): 
TID: -684419328
TID: -684419328
TID: -673929472
TID: -673929472
TID: -694909184
TID: -694909184
...
Actual (Sometimes): 
TID: -684419328
TID: -684419328
TID: -684419328
TID: -684419328
TID: -684419328
TID: -684419328
...
pthread_cond_t qServiced = PTHREAD_COND_INITIALIZER;
pthread_cond_t qElement = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
#include "rw.h"
#include "queue.h"

queue* q; 

void* reader()
{
    int serviced = 0; 
    int x; 

    while(!fin)
    {
        pthread_mutex_lock(&mutex);
        counter++; 

        while(isEmpty(q))
        {
            pthread_cond_signal(&qEmpty);
            pthread_cond_wait(&qElement, &mutex); e 
        }

        printf("TID: %d\n", (int)pthread_self());

        num* n = dequeue(q); //Take one task 

        printf("Num1: %d\n", n->num1);
        printf("Num2: %d\n", n->num2);

        serviced++;
        pthread_cond_signal(&qServiced); //Signal that task has been serviced
        pthread_mutex_unlock(&mutex);
    }
}

Ответы [ 2 ]

1 голос
/ 20 апреля 2019

Следующий предложенный код предназначен только для потока 'read ()', но он должен дать вам представление о том, как писать потоки.

void* reader( void *arg )
{
    int *fin = (int*)arg;

    int serviced = 0; 

    while( !(*fin) )
    {
        printf("TID: %d\n", (int)pthread_self());

        pthread_mutex_lock(&mutex);
        counter++; 
        num* n = dequeue(q); //Take one task 
        pthread_mutex_unlock(&mutex);

        if( n )
        {
            printf("Num1: %d\n", n->num1);
            printf("Num2: %d\n", n->num2);
            serviced++;
        }

        else
        {
            printf( "no queue entries available\n" );
            sleep(1);
        }
    }
    pthread_exit( NULL );
}

обратите внимание, что мьютекс блокируется, только когда поток выполняет действия, которые могут привести к состоянию 'гонки'.

В предлагаемом коде предполагается (поскольку код обработки очереди не был опубликован), что dequeue() возвращает NULL, если очередь пуста

Примечание: когда запись в очереди недоступна, поток некоторое время спит

Предполагается, что функция main () передает адрес 'fin' в качестве параметра в вызове pthread_create()

0 голосов
/ 22 апреля 2019

Планирование потоков запланировано одним из механизмов планирования.Но, как программист, вы должны предполагать, что это может быть любой случайный путь и код.

Говоря «случайный путь», я имею в виду, что все потоки могут быть запланированы один раз в ходе программы, или только один поток получаетзапланировано на весь курс.

Тема может быть запланирована случайным образом. Я надеюсь, что это отвечает на ваш вопрос.

Если вы хотите конкретный способ, которым выполнениедолжно произойти (пример: все потоки читаются один раз, прежде чем поток читается во второй раз), тогда вы должны соответствующим образом кодировать.Для этого вы можете использовать мьютекс, семафоры, сигналы условий, флаги и их комбинации.

...