Russian Qt Forum
Ноябрь 22, 2024, 23:29 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Неинтуитивный QThread  (Прочитано 10342 раз)
Akon
Гость
« : Сентябрь 04, 2011, 00:33 »

Огромным достоинством Qt является ее интуитивный API. Приведеный ниже код, имхо, интуитивно корректный, но на деле нет - он может работать, а может и дэдлокнуться.

Код:
	QApplication app(argc, argv);

QThread thread;
thread.start();
thread.exit();
thread.wait();

return 0;

Ваши мнения?
Записан
niXman
Гость
« Ответ #1 : Сентябрь 04, 2011, 00:36 »

человеческий фактор? Подмигивающий
Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #2 : Сентябрь 04, 2011, 03:11 »

а может и дэдлокнуться
И когда же он может дэдлокнуться?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Сентябрь 04, 2011, 09:41 »

exit завершает eventLoop, но он мог еще не быть запущен
Записан
Akon
Гость
« Ответ #4 : Сентябрь 04, 2011, 09:51 »

Дэдлок будет, если thread.exit() будет вызван до создания эвентлупа потока. Т.е. exit() не ставит признак того, что поток должен быть завершен при создании эвентлупа. Другими словами, у пользователя потока появляется проблема - дождаться запуска эвентлупа, и только тогда вызвать exit(). Такого функционала я не нашел в кьюте (возможно, плохо искал).
Навскидку, пара рабочих вариантов:

Код:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);

QThread thread;
thread.start();

do thread.exit();
while (!thread.wait(0));

return 0;
}

Код:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);

QThread thread;
thread.start();

{
QObject* dummy = new QObject;
dummy->moveToThread(&thread);
QMetaObject::invokeMethod(dummy, "deleteLater", Qt::BlockingQueuedConnection,
QGenericArgument(), Q_ARG(QObject*, dummy));
}

thread.exit();
thread.wait();

return 0;
}
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Сентябрь 04, 2011, 10:19 »

Другими словами, у пользователя потока появляется проблема..
Так это хорошо - может тот пользователь думать начнет (а не только пулять сигналами и всасывать Ассыстент  Улыбающийся)
Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #6 : Сентябрь 04, 2011, 11:09 »

Akon, честно говоря не удалось воспроизвести описанную вами ситуацию.
Но если уверены, что гонка возможна: http://bugreports.qt.nokia.com/
Может даже в 4.8.0 успеете.
Записан
Akon
Гость
« Ответ #7 : Сентябрь 04, 2011, 11:32 »

Отнаследуйтесь и в наследнике сделайте паузу перед вызовом QThread::run().

Это не баг, в доках все описано. Просто неинтуитивно, имхо. Если я вызвал QThread::exit(), то мне не хочется знать, зашел ли поток в эвенлуп или еще нет. Следуя логике QThread::exit() вызов invokeMethod
Код:
	{
QObject* dummy = new QObject;
dummy->moveToThread(&thread);
QMetaObject::invokeMethod(dummy, "deleteLater", Qt::BlockingQueuedConnection,
QGenericArgument(), Q_ARG(QObject*, dummy));
}
тоже можно послать, т.к. эвентлупа еще нет. Однако, вызов не теряется! На этом и основан мой второй вариант.

Да и сорец, имхо, неинтуитивный Улыбающийся
Код:
void QThread::exit(int returnCode)
{
    Q_D(QThread);
    QMutexLocker locker(&d->mutex);
    d->data->quitNow = true;
    for (int i = 0; i < d->data->eventLoops.size(); ++i) {
        QEventLoop *eventLoop = d->data->eventLoops.at(i);
        eventLoop->exit(returnCode);
    }
}
Я, когда писал код, поверхностно просмотрел QThread::exit() и тупо купился купился на d->data->quitNow = true;  Улыбающийся
« Последнее редактирование: Сентябрь 04, 2011, 11:41 от Akon » Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #8 : Сентябрь 04, 2011, 16:51 »

Отнаследуйтесь и в наследнике сделайте паузу перед вызовом QThread::run().
Может в этом и проблема, а не в QThread?

Вообще вызов exit до exec проблемы не вызывает:

Код:
class Thread : public QThread
{
public:
    void run()
    {
        sleep( 2 );
        qDebug( "exec" );
        exec();
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    Thread thread;
    thread.start();
    qDebug( "start" );
    thread.exit();
    qDebug( "exit" );
    thread.wait();
    return 0;
}


Цитировать
start
exit
exec
Записан
Akon
Гость
« Ответ #9 : Сентябрь 04, 2011, 17:05 »

Блокировка в wait(). Сделайте sleep(1000), sleep(2) это ничто по сравнению с ку-дебагами.
« Последнее редактирование: Сентябрь 04, 2011, 17:07 от Akon » Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #10 : Сентябрь 04, 2011, 17:11 »

Сделайте sleep(1000)
sleep(1000) - это 1000 секунд, т.е. 16,(6) минут.
Я конечно могу подождать, но...

UPD ну и даже при паузе в 17 минут ничего не дэдлочится (но 17 минут прождать приходится, разумеется).
« Последнее редактирование: Сентябрь 04, 2011, 17:35 от LisandreL » Записан
Akon
Гость
« Ответ #11 : Сентябрь 04, 2011, 17:38 »

Что у вас за sleep()? Время в миллисекундах.
...
И правда, void QThread::sleep ( unsigned long secs )  в секундах  Улыбающийся
« Последнее редактирование: Сентябрь 04, 2011, 17:41 от Akon » Записан
BRE
Гость
« Ответ #12 : Сентябрь 04, 2011, 17:41 »

Что у вас за sleep()? Время в миллисекундах.
void QThread::sleep ( unsigned long secs ) [static protected]
void QThread::usleep ( unsigned long usecs ) [static protected]
void QThread::msleep ( unsigned long msecs ) [static protected]

Аааа, это про вендовый Sleep...?
« Последнее редактирование: Сентябрь 04, 2011, 17:43 от BRE » Записан
Akon
Гость
« Ответ #13 : Сентябрь 04, 2011, 17:51 »

Цитировать
Аааа, это про вендовый Sleep...?
Я просто был уверен, что QThread::sleep() в миллисекундах. Забыл, когда последний раз им пользовался.
Записан
Akon
Гость
« Ответ #14 : Сентябрь 04, 2011, 17:58 »

2LisandreL:
У вас программа не завершается. Вы напишите дебаг после thread.wait().
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.074 секунд. Запросов: 22.