В своем проекте пытаюсь реализовать подобие механизма async/await
операций на Qt c использование QEventLoop
. Приведу простейший пример окна с одной кнопкой, по нажатию которой должен вызывать код, не блокирующий основной (GUI) поток.
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QPushButton *button = new QPushButton("button",this);
connect(button,&QPushButton::clicked,this,&MainWindow::onClicked);
}
void MainWindow::onClicked()
{
qDebug() << time() << " onClicked start ";
QEventLoop loop;
QtConcurrent::run([&loop]() {
qDebug() << time() << " Thread start: " << (void*)QThread::currentThread();
//doSomething
QThread::currentThread()->sleep(10);
QMetaObject::invokeMethod(&loop,"quit",Qt::QueuedConnection)
qDebug() << time() << " Thread finish: " << (void*)QThread::currentThread();
});
loop.exec();
qDebug() << time() << " onClicked finish ";
}
При однократном нажатии все замечательно, QtConcurrent
запустит задачу, которая выполнится в отдельном потоке, а loop.exec()
остановит выполнение функции, но не заблокирует EventLoop
всего приложения, окно будет активно, кнопку можно будет нажать еще.
В отладчике будет выведено, примерно следующее:
16:57:08.774 onClicked start
16:57:08.775 Thread start: 0xa83230
16:57:18.775 Thread finish: 0xa83230
16:57:18.775 onClicked finish
Если нажать кнопку несколько раз, то слот вызовется несколько раз и при каждом вызове создадутся объекты QEventLoop
, которые остановят выполнение слота в ожидании окончания асинхронных задач, что очевидно.
НО
Выход из цикла обработки событий у этих объектов произойдет одновременно по окончанию последней асинхронной задачи, т.е. после вызова последнего слота quit()
В отладчике следующее:
17:26:28.464 onClicked start
17:26:28.464 Thread start: 0xa83230
17:26:30.988 onClicked start
17:26:30.988 Thread start: 0x8dae20
17:26:37.549 onClicked start
17:26:37.549 Thread start: 0xa349c0
17:26:38.464 Thread finish: 0xa83230
17:26:40.989 Thread finish: 0x8dae20
17:26:47.549 Thread finish: 0xa349c0
17:26:47.549 onClicked finish
17:26:47.549 onClicked finish
17:26:47.549 onClicked finish
Вопрос: почему при создании нескольких объектов QEventLoop
, они заканчивают свои циклы обработки только после вызова слота quit()
каждого из объектов и как это изменить?
В Qt используется приватный мьютекс у объекта потока (QThread
) с атомарным счётчиком ссылок (QAtomicInt
):
// qeventloop.cpp, стр. 164
QMutexLocker locker(&static_cast<QThreadPrivate *>
(QObjectPrivate::get(d->threadData->thread))->mutex);
Соответственно, если поток, в котором существуют экземпляры QEventLoop
, один и тот же, то покуда счётчик ссылок quitLockRef
(см. файл qeventloop_p.h) не уйдёт в ноль, каждый инстанс QEventLoop
будет бесконечно крутиться в собственном цикле.
Для организации асинхронной реакции на завершение работы QtConcurrent
лучше всего подходит QFutureWatcher
:
void MainWindow::onClicked() {
qDebug() << time() << " onClicked start ";
QFutureWatcher<void> *watcher = new QFutureWatcher<void>(this);
connect(watcher, &QFutureWatcher<void>::finished
, this, [this,watcher]() {
qDebug() << time() << " onClicked finish ";
watcher->deleteLater();
});
QFuture<void> future
= QtConcurrent::run([this]() {
qDebug() << time() << " Thread start: "
<< (void*)QThread::currentThread();
//doSomething
QThread::currentThread()->sleep(10);
qDebug() << time() << " Thread finish: "
<< (void*)QThread::currentThread();
});
watcher->setFuture(future);
}
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Разработать метод-член класса для нового файла, содержащего
Доброго дня! Есть где-нибудь в доступе готовый натренированный, например на twitter или дрсоцсетях, файл word2vec с векторами?
Написал программу на вывод чисел в байтах и адреса хранения этих байтов,но преподаватель говорит,что адреса полей хранятся в сложных типах...
Программирую STM32 на C\C++, имеется кольцевой буфер входящих данных (не важно, текстовых или бинарных)Естественно известен формат данных, которые...