Как правильно читать поток C ++ 11 в контексте сервера, учитывая блокировку? - PullRequest
0 голосов
/ 19 февраля 2019

Учитывая, что все стандартные чтения потока C ++ 11 являются блокирующими, каков правильный способ чтения потока C ++ в контексте службы?Я попытался поместить блокирующие операции чтения внутри потока, но просто снова сталкиваюсь с блоком, когда пытаюсь присоединиться к потоку.

  • Рассмотрим следующую неудачную попытку решения.

У меня есть класс Reader, созданный с входным потоком, который может быть или не быть бесконечным (EOF) .

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

Метод остановки Reader должен присоединиться к потоку, но это объединение будет заблокировано, учитывая, что поток заблокирован на чтение!Аналогично для деструктора.

#include <iostream>
#include <thread>
#include <mutex>
#include <assert.h>

enum State {
    PRE, STARTED, STOPPED
};

class Reader {

    std::istream& source;
    State state { PRE };
    std::mutex mutex { };
    std::thread* myThread { nullptr };
    bool eof {false};
    bool error {false};

public:

    Reader(std::istream& source) :
            source(source) {
    }

    ~Reader() {
        if (myThread!=nullptr) {
            myThread->join();
        }
        delete myThread;
    }

    void start() {
        using namespace std;
        mutex.lock();
        if (state != PRE)
            throw -1;
        state = STARTED;

        myThread = new std::thread { [&]() {

            while(state==STARTED) {
                string line {};
                getline(source, line);

                if (source.eof()) {
                    mutex.lock();
                    state=STOPPED; // internal stop
                    eof=true;
                    mutex.unlock();
                    break;
                }

                if (!source.good()) {
                    mutex.lock();
                    state=STOPPED; // internal stop
                    error=true;
                    mutex.unlock();
                    break;
                }

                if (state==STARTED) { // may have been stopped externally
                    // do something important
                    cout << "'"<<line<<"'"<<endl;
                }
            }

        }

        };
        mutex.unlock();
    }

    void stop() {
        mutex.lock();
        if (state != STARTED)
            throw -2;
        state = STOPPED;
        myThread->join();
        delete myThread;
        myThread=nullptr;
        mutex.unlock();
    }

    bool isStarted() const {
        return state==STARTED;
    }
    bool isStopped() const {
        return state==STOPPED;
    }

    bool isEof() const {
        return eof;
    }

    bool isError() const {
        return error;
    }
};

int main() {
    using namespace std;

    Reader r { cin };
    r.start();
    cout << "[SLEEPING]..." << endl;
    this_thread::sleep_for(chrono::seconds(6));
    cout << "...[AWAKE]" << endl;
    cout << "[EOF:"<<to_string(r.isEof())<<"]" << endl;
    cout << "[ERROR:"<<to_string(r.isError())<<"]" << endl;
    cout << "[STILL STARTED:"<<to_string(r.isStarted())<<"]" << endl;
    if (r.isStarted()) {
        cout << "[STOPPING]..." << endl;
        r.stop();
        cout << "...[STOPPED]" << endl;
    }
    cout << "[EXIT]" << endl;
    return 0;
}

Основная функция демонстрирует проблему.Reader создается с помощью std :: cin и запускается.Затем основной поток некоторое время спит.

Когда основной поток просыпается, он проверяет, все ли еще запущено устройство чтения (что будет, если не возникла ошибка или EOF) .Если Reader все еще запущен (в этом случае поток заблокирован для чтения) , мы останавливаем Reader.

  • Но эта остановка блокируется при попытке присоединиться к потоку.

Если вы запустите код (ссылка с pthread) и нажмете Ctrl-D в течение периода ожидания, все завершится корректно (после сна, конечно) .

Но если вы ожидаете период ожидания, программа останавливается и никогда не завершается.

  • Как решить эту проблему в чистом C ++ 11?Разве это невозможно?

Конечно, есть нестандартные решения, но можно ли это сделать только на C ++?

...