2013-10-12 8 views
0

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

Я думал, что лучший способ сделать это состоял в том, чтобы запустить 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 Однако, когда приложение завершает работу графического интерфейса, поток застрянет и никогда не выходит. Я также попытался использовать QMutex, однако gui станет заблокированным, ожидая мьютекс, который заблокирован и используется длинной функцией.

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

ответ

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, если вы делаете это из графического интерфейса нити и myObject->thread() ненулевая: Вы не можете удалять объекты, которые имеют резьбу сродством иначе, чем текущий поток. Аффинность нулевой нити означает, что нить нить не требует объекта - в нашем случае, когда поток объекта разрушен. Тогда любой поток может удалить его.

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

+0

Это решило все мои проблемы! – Dave