Пишу GUI приложение на Qt
Что хочется:
[list=1] GUI поток
[list=2] Background поток
Механизм ообщения:
Background поток висит все время получает запросы на работу, отправляет результаты работы и лог-сообщения, общение происходит через slots/signals
Что сделал:
class CBackgroundStorage::QThread с пустым методом run() и отписал слоты
Что имею:
Первым же делом CBackGroundStorage принимается парсить файлы (очень длительный процесс), но GUI при этом подвисает и лог сообщения не показывает — я так понимаю, что никакой многопоточности фактически нет
Вопрос — что делать, чтоб многопоточность появилась? У меня такое подозрение, что что-то в корне не так. Если не понятно то буду писать минимумпример
21.01.10 13:02: Перенесено модератором из 'C/C++. Прикладные вопросы' — Кодт
H>Вопрос — что делать, чтоб многопоточность появилась? У меня такое подозрение, что что-то в корне не так. Если не понятно то буду писать минимумпример
Наверное стоит. потому что приведенный фрагмент нежизнеспособен -- как минимум отсутствует QApplication.
Здравствуйте, hotdox, Вы писали:
H>Вопрос — что делать, чтоб многопоточность появилась? У меня такое подозрение, что что-то в корне не так. Если не понятно то буду писать минимумпример
советую посмотреть примеры... почитать документацию по Qt...
С уважением Denys Valchuk
IMHO чем больше мнений тем оптимальней выбор варианта... :)
Здравствуйте, hotdox, Вы писали:
H>Здравствуйте, Denys V., Вы писали:
DV>>советую посмотреть примеры... почитать документацию по Qt...
H>Даже книги читал, там не описаны подобные случаи H>Сделал минимумпример весь проект — http://rghost.ru/239203
Экземпляр QThread "находится" в потоке-родителе (переменная находится в том потоке, где создана). Соответственно все твои слоты в главном потоке вызываются. А новый созданный поток "живет" только пока QThread::run выполняется — в твоем случае очень не долго. Ну и is_run переменная — источник проблем: присваивание is_run=false за счет переупорядочивания инструкций процессором и компилятором может произойти до того, как расчет завершится.
Здравствуйте, little_alex, Вы писали:
_>Экземпляр QThread "находится" в потоке-родителе (переменная находится в том потоке, где создана). Соответственно все твои слоты в главном потоке вызываются. А новый созданный поток "живет" только пока QThread::run выполняется — в твоем случае очень не долго.
Меня смущал пример с таймером и полоской прогресса, но там таймер создается в run() и его сигналы вызываются не из главного потока.
_>Ну и is_run переменная — источник проблем: присваивание is_run=false за счет переупорядочивания инструкций процессором и компилятором может произойти до того, как расчет завершится.
Это такой самодельный мьютекс, не обращайте внимания
Здравствуйте, hotdox, Вы писали:
H>Здравствуйте, Denys V., Вы писали:
DV>>советую посмотреть примеры... почитать документацию по Qt...
H>Даже книги читал, там не описаны подобные случаи H>Сделал минимумпример весь проект — http://rghost.ru/239203
Что бросилось в глаза:
1) В конструкторе потока надо вызвать moveToThread(this);
Иначе все signal/slot соединения будут работать в контексте потока,
где ты создал свой объект (в твоем случае — главный поток)
2) метод run у тебя пустой. Это означает, что поток запускается и сразу останавливается.
В методе run надо вызвать метод exec, чтобы запустить цикл обработки сообщений потока.
То, что у тебя, запускает поток, который тут же завершается, и вся обработка происходит в главном потоке.
Здравствуйте, bkat, Вы писали:
B>1) В конструкторе потока надо вызвать moveToThread(this); B>В методе run надо вызвать метод exec, чтобы запустить цикл обработки сообщений потока.
Внес исправления, и все заработало как надо, большое спасибо!
Однако еще вопрос: что делать если поток занят работой, а приложение закрыли — появляется ошибка и предлагается сохранить bugreport
попробовал разные варианты
Здравствуйте, hotdox, Вы писали:
H>Здравствуйте, bkat, Вы писали:
B>>1) В конструкторе потока надо вызвать moveToThread(this); B>>В методе run надо вызвать метод exec, чтобы запустить цикл обработки сообщений потока.
H>Внес исправления, и все заработало как надо, большое спасибо!
H>Однако еще вопрос: что делать если поток занят работой, а приложение закрыли — появляется ошибка и предлагается сохранить bugreport
Ожидаемый вопрос
У тебя скорей всего поток все еще работает, после того, как объект CBackgroundWorker уже разрушен.
По хорошему, тебе надо попросить поток завершить полезную работу (именно попросить, а не убить поток),
потом завершить цикл обратки сообщений потока и завершить сам поток.
Главный поток должен ждать пока поток не завершиться и только после этого можно
уничтожать объект CBackgroundWorker.
Способов это сделать уйма.
Попробуй, к примеру так (твой код с дополнениями):
int main(int argc, char *argv[]){
QApplication a(argc, argv);
MainWindow w;
CBackgroundWorker worker;
QObject::connect(&w, SIGNAL(start()), &worker, SLOT(work()));
QObject::connect(&worker, SIGNAL(Log(QString)), &w, SLOT(getLog(QString)));
worker.start();
w.show();
int rc = a.exec();
worker.quit(); // просим завершить цикл обработки сообщений потока
worker.wait(); // ждем пока поток не завершит свою работуreturn rc;
}
Одна проблема тут точно есть.
До тех пор пока CBackgroundWorker::work() что-то делает, цикл обработки сообщений потока не завершится
и тем самым приложение будет висеть, пока CBackgroundWorker::work() не доделает то,
что все равно никому не нужно (приложение ведь закрывается).
Если это проблема, то тебе надо будет подумать, как в CBackgroundWorker::work() передать твое
пожелание завершить работу как можно скорее.
Банального bool флага должно хватить за глаза.
Здравствуйте, hotdox, Вы писали:
H>Пишу GUI приложение на Qt H>Что хочется: H> [list=1] GUI поток H> [list=2] Background поток H> Механизм ообщения: H> Background поток висит все время получает запросы на работу, отправляет результаты работы и лог-сообщения, общение происходит через slots/signals H>Что сделал: H> class CBackgroundStorage::QThread с пустым методом run() и отписал слоты H>
H>Что имею: H> Первым же делом CBackGroundStorage принимается парсить файлы (очень длительный процесс), но GUI при этом подвисает и лог сообщения не показывает — я так понимаю, что никакой многопоточности фактически нет
H>Вопрос — что делать, чтоб многопоточность появилась? У меня такое подозрение, что что-то в корне не так. Если не понятно то буду писать минимумпример
Чтоб слоты отрабатывались в другом потоке, этот другой поток должен содержать цикл обработки сообщений. Т.о. в QThread::run() нужно вызвать QThread::exec()
Ну и, как уже отмечали выше, main() у тебя не правильно составлен. Он тоже должен содержать цикл обработки сообщений для основного потока, т.е. QApplication::exec()
А также надо написать код завершения потока при выходе из приложения (хотя, возможно, Qt сам умеет разбираться с этим, надо глянуть в исходниках деструктор класса QThread).
Прошлое забыто. Будущее закрыто. Настоящее даровано. (с) одна мудрая черепаха