Russian Qt Forum

Qt => Вопросы новичков => Тема начата: titan83 от Октябрь 07, 2013, 15:05



Название: QThread и бесконечный цикл в потоке
Отправлено: titan83 от Октябрь 07, 2013, 15:05
Здравствуйте.
Попользовался и гуглом, и местным поиском, но так и не решил свою проблему, поэтому пишу.
Есть поток, в котором вызывается poll() для контроля файлов на sysfs, это поток оформлен в виде бесконечного цикла, и именно его зацикленность порождает сообщение - QThread: Destroyed while thread is still running, но сообщение бы можно было игнорировать, а вот процесс-зомби уже мешает - приложение после этого повторно не запускается - завершается с кодом 0 на функции QThread::start().
Возможно, что я действую идеологически неправильно, тогда было бы здорово получить пинок в нужное направление.
Спасибо.
Привожу основные моменты кода:

class QMyObject: public QObject
{
Q_OBJECT

public slots:
    void getKey(int keyCode)
    {
        if (keyCode == -1)
        {
            emit exit();
        }
    }
signals:
    void exit(void);

};

class PollThread : public QThread
{
Q_OBJECT

private:

public:
    void run()
    {
        while(true)
        {
            poll(fdset, 2, 500);

            if (fdset[1].revents & POLLPRI)
            {
                switch (rx[0])
                {
                } /* switch (rx[0]) */

                emit keyPressed(keyCode);
            } /* if (fdset[0].revents & POLLPRI) */
        } /* while(true) */
    } /* void run() */

signals:
    void keyPressed(int);
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    PollThread keyb_thread;
    QMyObject myObject;

    QObject::connect(&keyb_thread, SIGNAL(keyPressed(int)), &tabWidget, SLOT(setCurrentIndex(int)));
    QObject::connect(&keyb_thread, SIGNAL(keyPressed(int)), &myObject, SLOT(getKey(int)));
    QObject::connect(&keyb_thread, SIGNAL(finished()), &myObject, SLOT(deleteLater()));
    QObject::connect(&myObject, SIGNAL(exit()), &a, SLOT(closeAllWindows()));

    keyb_thread.start();

    return a.exec();
}


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: mutineer от Октябрь 07, 2013, 15:19
Завершай поток перед тем, как уничтожать связанный с ним QThread. Например заведи volatile переменную и проверяй ее на каждой итерации цикла.


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: titan83 от Октябрь 07, 2013, 15:43
Завершай поток перед тем, как уничтожать связанный с ним QThread. Например заведи volatile переменную и проверяй ее на каждой итерации цикла.
Спасибо. Как я понимаю - это обычный return?
Надеялся, что без это удастся обойтись.


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: mutineer от Октябрь 07, 2013, 15:59
Да, надо выйти из run()

Ну и перед удалением QThread подождать его при помощи wait()


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: kuzulis от Октябрь 07, 2013, 16:28
a select() вместо poll() может спасти отца русской демократии? :)


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: mutineer от Октябрь 07, 2013, 16:31
А чем оно поможет? Разве select неблокирующий?


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: kuzulis от Октябрь 07, 2013, 16:32
А тем, что можно убрать QThread и использовать QSocketNotifier :)


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: mutineer от Октябрь 07, 2013, 16:35
Извини, но я не вижу связи между заменой poll() на select() и заменой всего этого на QSocketNotifier. Можешь пояснить?


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: kuzulis от Октябрь 07, 2013, 16:39
Код
C++ (Qt)
 
QSocketNotifier sysfsNotifier(ourWatchedSysfsDescriptor);
 
connect(sysfsNotifier, SIGNAL(activated(int)), this, SLOT(onActivated(int)));
sysfsNotifier.setEnabled(true);
 
 
MyClass::onActivated(int)
{
   // do something
}
 
 


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: mutineer от Октябрь 07, 2013, 16:40
А где тут замена poll на select?


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: kuzulis от Октябрь 07, 2013, 16:41
Эмм.. QSocketNotifier использует select() если не ошибаюсь. Поэтому, если ТС-у можно заменить poll() на select(), то можно заменить весь его Thread на QSocketNotifier (или на несколько ) и не парить мосг.

Т.е. следить за дескриптором в *nix (за евентами типа read/write/error) достаточно при помощи QSocketNotifier.


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: titan83 от Октябрь 08, 2013, 10:19
Эмм.. QSocketNotifier использует select() если не ошибаюсь. Поэтому, если ТС-у можно заменить poll() на select(), то можно заменить весь его Thread на QSocketNotifier (или на несколько ) и не парить мосг.

Т.е. следить за дескриптором в *nix (за евентами типа read/write/error) достаточно при помощи QSocketNotifier.
Денис, спасибо! То, что надо!
А то FileWatcher базируется на inotify, о она события на sysfs не ловит(


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: titan83 от Октябрь 08, 2013, 13:31
Хм, а у меня получить адекватную работу QSocketNotifier пока не получилось(
В слоте от нотифера я вычитываю данные из наблюдаемого файла, как я это делал раньше с select(), при этом удается прочесть адекватные данные только один раз, потом read() всегда возвращает число считанных байт ноль. Пробовал вычитывать и ReadAll() и просто read() из stdio - результат одинаковый. А раз я не вычитываю, то у меня сыплются постоянные прерывания от нотифера. Может есть пример заведомо рабочего кода?
Спасибо.


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: kuzulis от Октябрь 08, 2013, 14:27
Покажи твой код с QSocketNotifier.


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: titan83 от Октябрь 08, 2013, 14:48
Тут проблема не в нотифире, видимо. Делаю просто

            file = open("/test", O_RDWR | O_NONBLOCK);

            while(true)
            {
                read(file, &c, 1);
                qDebug() << QString::number(c);
                read(file, &c, 1);
                qDebug() << QString::number(c);
            }
Файл содержит два байта - 52 и 10.
В первой итерации цикла все читается правильно, потом оба байта читаются как 10.
Посмотрел свои проекты на чистом си - там все аналогично происходит с select() и все работает.


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: titan83 от Октябрь 08, 2013, 14:54
Извиняюсь - сам туплю нещадно, это ж позиция чтения из файла, просто не выставляется(


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: titan83 от Октябрь 08, 2013, 15:07
Но с нотифером это ситуация, к сожалению, не прояснило. Поэтому выкладываю код:

    gpio_fd = open("/test", O_RDONLY | O_NONBLOCK );

    inputNotifier = new QSocketNotifier(gpio_fd, QSocketNotifier::Read);
    inputNotifier->setEnabled(true);
    QObject::connect(inputNotifier, SIGNAL(activated(int)), &myObject, SLOT(getKey(int)));

    void getKey(int k)
    {
        int ret;
        int buf = 10;
        QByteArray data;

        lseek(gpio_fd, 0, SEEK_SET);
        ret = read(gpio_fd, &buf, 2);
        if (ret < 0)
        {
            perror("read value");
        }

        {
            qDebug() << "value" << QString::number(buf);

            data = kDevice.read(1);
            qDebug() << "spidev" << QString::number(data[0], 16);
        }
    }

После прописывания функции позиционирования значение читается правильное, флаг готовности чтения select() не сбрасывается.


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: kuzulis от Октябрь 08, 2013, 16:36
Цитировать
флаг готовности чтения select() не сбрасывается.

Это может быть если не все данные прочитаны. Если есть возможность узнать сколько доступно байт - то надо сделать это.
Или читать не два байта а 1024 сразу, т.к. в любом случае вернется столько, сколько доступно.

Хотя я не в курсе как мониторить sysfs, возможно есть какие-то особенности и т.п. тут ничем помочь не могу.

Хотя, можешь в getKey() еще раз вызвать select() с нулевым таймаутом && FD_ISSET. Может поможет :).
Также можно в getKey() проверять номер дескриптора k ==  gpio_fd.


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: titan83 от Октябрь 09, 2013, 07:42
Странная канитель.
Я, причем, сейчас все это делаю даже не на sysfs, хотя для select() разницы так-то нет - по дескрипторам же наблюдается.
Без Qt select() работает отлично.
Ладно, сегодня поразбираюсь, если что-то получится, то отпишусь.


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: titan83 от Октябрь 09, 2013, 12:59
Если кому интересно, то проблема с select() в том, что он реагирует на EOF, т.е. надо закрывать и снова открывать файл, а это не то, что нам надо.
Читал разные комменты в сети, но так и не увидел приемлемого решения.
to kuzulis. Хотел у тебя проконсультироваться по поводу разработки своего компонента (как к разработчику QtSerialPort), сделать аналог QsocketNotifier, но на основе poll(), пока буду читать исходники этих компонент, чтобы понять основные принципы построения.
Как для тебя ненапряжнее будет общение? Создать здесь ветку?


Название: Re: QThread и бесконечный цикл в потоке
Отправлено: kuzulis от Октябрь 09, 2013, 13:57
Цитировать
Хотел у тебя проконсультироваться по поводу разработки своего компонента (как к разработчику QtSerialPort), сделать аналог QsocketNotifier, но на основе poll(), пока буду читать исходники этих компонент, чтобы понять основные принципы построения.

Это не просто, потому что тебе придется лезть в кишки Qt и патчить их.
Класс QsocketNotifier - это всего-лишь верхушка айсберга, всеми евентами заправляет EventDispatcher.
Т.е. там все прибито гвоздями к select() (если не ошибаюсь).

Т.е. тебе придется или лезть в кишки и что-то там менять, или создать свой класс PollNotifier (или как там его) с использованием отдельного потока.

По поводу отдельного потока можешь зделать что-то аналогичное QWinOverlappedNotifier (https://qt.gitorious.org/qt/qtbase/source/51c28cad67077500f63dbe8c0060ed19cf340c0d:src/corelib/io/qwinoverlappedionotifier_p.h) но только для Linux. Это будет самое простое, ИМХО. :)
 

Цитировать
Как для тебя ненапряжнее будет общение? Создать здесь ветку?

Эмм.. В принципе у меня нет времени и интереса к этой теме. :)


Название: Re: QThread и бесконечный цикл в потоке [решено]
Отправлено: titan83 от Октябрь 10, 2013, 08:41

Это не просто, потому что тебе придется лезть в кишки Qt и патчить их.
Класс QsocketNotifier - это всего-лишь верхушка айсберга, всеми евентами заправляет EventDispatcher.
Т.е. там все прибито гвоздями к select() (если не ошибаюсь).

Т.е. тебе придется или лезть в кишки и что-то там менять, или создать свой класс PollNotifier (или как там его) с использованием отдельного потока.

По поводу отдельного потока можешь зделать что-то аналогичное QWinOverlappedNotifier (https://qt.gitorious.org/qt/qtbase/source/51c28cad67077500f63dbe8c0060ed19cf340c0d:src/corelib/io/qwinoverlappedionotifier_p.h) но только для Linux. Это будет самое простое, ИМХО. :)
Кишки глянул, EventDispatcher понял, что пока мне это не потянуть, да и не надо.
Буду делать по аналогии с http://qt-project.org/forums/viewthread/25465
Эмм.. В принципе у меня нет времени и интереса к этой теме. :)
Да я не имел в виду, что хочу привлечь тебя бесплатным консультантом и парить по каждой мелочи))
Буду, когда совсем невмоготу, писать тут на форуме.
Еще раз спасибо за помощь!
Тема закрыта.