Название: 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 Код
Название: 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. Это будет самое простое, ИМХО. :) Буду делать по аналогии с http://qt-project.org/forums/viewthread/25465 Эмм.. В принципе у меня нет времени и интереса к этой теме. :) Да я не имел в виду, что хочу привлечь тебя бесплатным консультантом и парить по каждой мелочи))Буду, когда совсем невмоготу, писать тут на форуме. Еще раз спасибо за помощь! Тема закрыта. |