Дизайн синхронизации потоков Qt

0

У меня проблемы с дизайном, который уже довольно долго меня пугал. По сути, у меня есть функция, которая требует много времени для выполнения и gui, которая должна быть отзывчивой и актуальной. Когда пользователь нажимает кнопку запуска, длинная функция начинает выполняться в цикле while, и после каждого выполнения gui необходимо обновить.

Я думал, что лучший способ сделать это - запустить QThread в цикле while, и если пользователь нажал кнопку запуска, начнется длительная функция. аналогично следующему:

class Application : public QThread
{
    void run (void)
    {
        while (!mExiting)
        {
            if (StartPressed)
                LongFunction();

            // Need to update gui before
            // running long function again
        }
    }
}

Я попытался выполнить QMetaObject :: Invoke с BlockingQueuedConnection, однако, когда приложение gui завершает работу, поток застревает и никогда не выходит. Я также попытался использовать QMutex, однако gui станет заблокированным, ожидая мьютекс, который заблокирован и используется длинной функцией.

Я думал, есть ли способ отменить BlockingQueuedConnection, когда приложение хочет выйти, или есть какой-то другой способ его реализации.

Теги:
multithreading
user-interface
qt
thread-safety

1 ответ

1
Лучший ответ

Вы близки, но вам не нужно наследовать от QThread. Вместо:

  1. Поместите вычисление в слот в QObject.

  2. Поместите код, который устанавливает флаг выхода в другой слот (скажем Q_SLOT void finish();)

  3. Создайте экземпляр объекта. Создайте экземпляр QThread. Вызовите myObject->moveToThread(myThread).

  4. Запустите нить.

  5. Подключите сигналы gui к слотам в вычислительном объекте, аналогично подключите сигналы в объекте вычисления, которые указывают, что данные готовы.

  6. Чтобы завершить обработку и завершить поток, предположив, что gui отправляет сигнал stop(), установите следующие соединения:

    1. connect(gui, SIGNAL(stop()), myObject, SLOT(finish()) - чтобы остановить вычисление

    2. connect(gui, SIGNAL(stop()), myObject->thread(), SLOT(quit())) - завершение цикла события в потоке

    3. connect(myObject->thread(), SIGNAL(finished()), myObject->thread(), SLOT(deleteLater()) - удалить поток при возврате метода run()

    Вам все равно нужно удалить myObject когда вы закончите получать от него результаты или, по крайней мере, до выхода вашего приложения.

Предупреждение. Ошибка delete myObject если вы делаете это из потока gui, и myObject->thread() отличен от нуля: вы не можете удалять объекты, которые имеют аффинность потока, отличную от текущей. Аффинность с нулевой нитью означает, что нить нитей не утверждает объект - в нашем случае, когда поток объекта разрушен. Тогда любой поток может удалить его.

По той же причине вы не можете moveToThread объект, у которого есть родитель. Объект, который вы перемещаете, может иметь детей, однако он просто не может иметь самого родителя.

  • 0
    Это решило все мои проблемы!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню