Fstream дает пустые строки при чтении файла, при использовании с pthreads - PullRequest
0 голосов
/ 07 августа 2020

Я пытаюсь реализовать задачу читателя-писателя при чтении / записи файла, а не просто переменной в C ++. Для этой цели я объявил глобальную переменную fstream, которая открывает файл. и две функции, одна для читателя, другая для писателя. Вот мой код:

#include<pthread.h>
#include<semaphore.h>
#include<iostream>
#include<fstream>

using namespace std;

/// One writer, multiple readers


// initialize the file to be read and write 
fstream file("text.txt",ios::in|ios::out|ios::app);

// declare semaphore and mutex
sem_t rw_semaphore;
pthread_mutex_t multiread_mutex;

// variable to keep track of number of readers
int readers = 0;

void *writer(void *arg){
    // try to get the semaphore for accessing the file
    sem_wait(&rw_semaphore);
    // write to the file
    file << "Wrote to the file.."<<*(int *)arg<<endl;
    cout<<"Writer no. "<<*(int *)arg<<" wrote to the file"<<endl;
    // signal realease of semaphore for accessing the file
    sem_post(&rw_semaphore);
}

void *reader(void *arg){
    // Lock mutex for accessing readers count variable
    pthread_mutex_lock(&multiread_mutex);
    readers++;
    // if this is the first reader, try to get the semaphore
    if(readers == 1){
        sem_wait(&rw_semaphore);
    }
    // release mutex lock
    pthread_mutex_unlock(&multiread_mutex);
    // read the file
    cout<<"Reader no: "<<*(int *)arg<<" reading file: -"<<endl;
    for(string line;getline(file,line);){
        cout<<line<<endl;
    }
    file.clear();
    // lock mutex
    pthread_mutex_lock(&multiread_mutex);
    readers--;
    // if this is the last reader, release the semaphore
    if(readers == 0){
        sem_post(&rw_semaphore);
    }
    // release mutex lock
    pthread_mutex_unlock(&multiread_mutex);
}

int main()
{
    pthread_t read[7], write[5];
    pthread_mutex_init(&multiread_mutex,NULL);
    sem_init(&rw_semaphore,0,1);
    int *arg = new int;
    for(int i=0;i<7;i++){
        *arg = i+1;
        pthread_create(&read[i],NULL,reader,(void *)arg);
    }
    for(int i=0;i<5;i++){
        *arg = i+1;
        pthread_create(&write[i],NULL,writer,(void *)arg);
    }

    for(int i=0;i<7;i++){
        pthread_join(read[i],NULL);
    }
    for(int i=0;i<5;i++){
        pthread_join(write[i],NULL);
    }

    pthread_mutex_destroy(&multiread_mutex);
    sem_destroy(&rw_semaphore);
    file.close();

    return 0;
}

Но cout, печатающий строки в файле, ничего не печатает. Вот результат, который я получаю:

Reader no: 2 reading file: -

Reader no: 3 reading file: -

Reader no: 4 reading file: -

Reader no: 5 reading file: -

Reader no: 6 reading file: -

Reader no: 7 reading file: -

Reader no: 1 reading file: -

Writer no. 2 wrote to the file
Writer no. 3 wrote to the file
Writer no. 3 wrote to the file

Писатель отлично записывает файл, и файл не пуст во время чтения. Что я делаю не так?

1 Ответ

0 голосов
/ 07 августа 2020

Недостаточная синхронизация считывателей. Вы не можете заставить несколько читателей одновременно пытаться прочитать что-то из одного объекта iostream.

Более того, @Basya уже намекнул, у вас неправильное представление о том, где вы находитесь в файле. У вас есть только один индекс в этом файле, который вы продолжаете продвигаться как при чтении, так и при записи. И который также изначально был расположен в конце файла.

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

Ваша последовательность также немного неверна. Как видно из результатов, ваши читатели опередили писателей. Плохое использование семафора и мьютекса. Вместо этого вы должны были использовать мьютекс для защиты file и семафор в качестве счетчика числа завершенных записей. Только от писателя, ждите только от читателя. Конечно, тогда двое из читателей будут голодать, но обычно у вас будет отдельное условие остановки для отслеживания после того, как все авторы будут присоединены. (И чтобы разбудить читателей после того, как было установлено условие остановки, вы бы снова увеличили семафор из основного потока.)

Также как общее практическое правило: не ждите семафор, пока вы удерживайте мьютекс, чтобы все было наоборот. Другое дело с условной переменной, так как у нее есть операции atomi c для переключения между владением мьютексом и ожиданием CV, но для семафора это означает, что вы ошиблись в использовании.

...