LINUX.ORG.RU

[C++] Остановить чтение файла из параллельного потока


0

1

В треде, параллельном основному UI-треду, происходит чтение входного файла. Используются стандартные потоки+boost. Файл может быть длинным, и этот тред иногда нужно принудительно останавливать. В некоторых случаях файл является fifo.

Входной файл состоит из записей, и в текущем виде тред после каждой прочитанной записи проверяет, не пришёл ли ему приказ завершиться. Этот метод не годится, так как если файл является fifo, и создающий его процесс был убит, не успев слелать запись полностью, либо не успев сделать ни одной записи, читающий файл тред зависнет в ожидании ввода.

Как сделать правильно? Нужно что-то вроде системного вызова select, но на потоках.

Ответ на: комментарий от geekless

В смысле QThread::terminate. Не кошерно, так как деструкторы не позовутся, память потечёт и т. д.

Mihai-gr ()

Ой, блин. ну правда, неужели совсем разучились думать читать и учиться ?

shm_open(shmfd)
while(1) {
 lseek(shmfd, 0)
 c = read(shmfd, 1)
 if (c) 
  exit(1);
 /* read file */
}

Jetty ★★★★★ ()

Да и вообще, любой механизм IPC подойдет....

Jetty ★★★★★ ()
Ответ на: комментарий от Jetty

>Ой, блин. ну правда, неужели совсем разучились думать читать и учиться ?

Ой, блин. ну правда, неужели совсем разучились читать текст вопроса ?

Проблема как раз таки в коде /* read file */, который ступорится, ожидая ввода, и который нужно из этого состояния вывести. Как послать сообщение, я и сам разобрался.

Mihai-gr ()

Входной файл состоит из записей
если файл является fifo

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

как вариант aio_read/aio_suspend с таймаутом.

mi_estas ()
Ответ на: комментарий от Mihai-gr

Неблокирующий I/O, это же очевидно :)
man select

Jetty ★★★★★ ()
Ответ на: комментарий от mi_estas

>aio_read/aio_suspend

Похоже, то, что мне нужно, называется асинхронный ввод.вывод. Буду смотреть в сторону asio.

Mihai-gr ()
Ответ на: комментарий от Jetty

>man select

Нужно что-то вроде системного вызова select, но на потоках.

Ну да, ну да.

Mihai-gr ()
Ответ на: комментарий от Mihai-gr

Почему не подходит просто select?
Селектишь из двух дескрипторов: в одном читаешь файл/фифо, в другом ожидаешь пинка со стороны GUI.

Manhunt ★★★★★ ()
Ответ на: комментарий от Mihai-gr

aio реально не нужен. Достаточно неблокирующего ИО :)

Jetty ★★★★★ ()
Ответ на: комментарий от Manhunt

>Почему не подходит просто select?

Boost.streams используется для прозрачной работы с компрессией. Можно, конечно, реализовать свой streambuf, который делает как раз-таки это, но, возможно, это кем-то уже сделано.

aio реально не нужен. Достаточно неблокирующего ИО :)

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

Mihai-gr ()
Ответ на: комментарий от Mihai-gr

Если вам нужно немедленное завершение чтения файла, то смотрите в сторону сигналов. Написать обработку так, чтобы на сигнал реагировал только один поток совсем не сложно.

delete83 ★★ ()
Ответ на: комментарий от Mihai-gr

а Boost.streams не может выдать хэндл, который подойдет для select ?

x905 ★★★★★ ()

В идеале нужно что-то вроде InterruptibleChannel из Java. Можно попробовать написать самому, но может в Boost'е уже есть что-то подобное?

Mihai-gr ()
Ответ на: комментарий от ckotinko

В Boost.iostreams, насколько я понял, всё синхронное. По крайней мере, беглый обзор reference не выдаёт ничего подходящего. А что конкретно вызывает ненависть?

Mihai-gr ()
Ответ на: комментарий от Mihai-gr

ненавижу писателей подобных сраных streams, потому что они говно

хочешь жить как людь - пиши свои классы, отдельные от убогих реализаций.

ckotinko ☆☆☆ ()
class FileReader : public QObject {
    Q_OBJECT

public:
    FileReader(const char *filename)
        : QObject(0)
    {
        int handle = ::open(filename, O_NONBLOCK | O_RDWR);
        m_notifier = new QSocketNotifier(handle, QSocketNotifier::Read, this);
        m_notifier->setEnabled(true);

        connect(m_notifier, SIGNAL(activated(int)), SLOT(readFile(int)));
    }

    ~FileReader() {
        qDebug() << Q_FUNC_INFO << ::close(m_notifier->socket());
    }

private slots:
    void readFile(int fd) {
        m_notifier->setEnabled(false);
        {
            QFile file;
            if (file.open(fd, QFile::ReadOnly)) {
                qDebug() << file.readAll();
            }
        }
        m_notifier->setEnabled(true);
    }

private:
    QSocketNotifier *m_notifier;
};

Фигота конечно, и вроде как QSocketNotifier не гарантируют корректную работу с pipe'ами.

И хрень с QFile лучше наверное таки заменить на обычный ::read.

anonymous ()

Лучше взять Boost.ASIO

Сделать для этого потока io_service, запустить туда тред, читать файл/пайп через async_read/async_read_until (там есть posix::stream_descriptor для заворачивания файловых дескрипторов), а когда надо убить, делать io_service.reset(), completion_handler будет вызван с boost::asio::error::operation_aborted.

ratatosk ()

Пока не напишу, не буду отмечать как решённую. Либо возьму Asio, либо попробую написать прерываемый фильтр для boost iostreams.

Mihai-gr ()
Ответ на: комментарий от Jetty

Лучше уж pselect() тогда чтоб не переходить в busy-wait.

ono ()
Ответ на: комментарий от ono

select() has no sigmask argument, and behaves as pselect() called with NULL sigmask.

Jetty ★★★★★ ()

Проще всего закрыть файловый дескриптор, который читает другой поток исполнения. Тогда системный вызов read() в том потоке вернёт ошибку EBADF.

iliyap ★★★★ ()
Ответ на: комментарий от iliyap

> Тогда системный вызов read() в том потоке вернёт ошибку EBADF.

Гонка же. Следующий открытый файл рискует занять тот же номер и будет не EBADF, а кошмар.

const86 ★★★★★ ()

Boost.asio вряд ли подойдёт. Хотя там и есть потоки, но асинхронно они только сообщяются с сокетами, операции чтения/записи из потока такие же блокирующие. Нельзя заставить эту операцию прерваться и кинуть исключение.

Остаётся вариант с реализацией streambuf с aio внутри.

Mihai-gr ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.