2013-04-09 68 views
1

對不起,這篇文章的長度。但我堅持了兩天吧....QThread無法啓動

我正在通過ActiveX與硬件設備通信的Qt 4.6 Windows應用程序。

當我發送一個命令時,設備會做一些事情,當它完成時(可能需要一分鐘)它會發出一個信號。我需要等待這個信號,以確定是否一切正常(或不),並採取一些行動。

當用戶單擊按鈕時,將向設備發送命令。顯然,我不希望HMI凍結。

我確信我必須使用線程。因此,我確定了三個線程:

  1. 對應於HMI
  2. 硬件控制器(被髮送的命令後,其鎖定和等待的信號)
  3. 硬件通知監聽器連續地從得到的信號的主線程硬件和解鎖線程2

下面是類圖:

class diagram]

和序列圖來展示我所看到的東西:

sequence diagram

說明:

當用戶啓動我的應用程序,創建HMI。 HMI的構造函數調用Worker的構造函數。它構造硬件QAxObject。然後它構造HardwareListener給出的參考:QAxObject,QMutex和QWaitCondition。然後,Worker的構造函數將HardwareListener對象移動到另一個線程並啓動它。最後,HMI的構造函數啓動Worker的線程。

然後,當用戶點擊一個按鈕時,HMI發送一個信號給工人。 Worker向硬件發送命令(該命令可能會在幾秒鐘內阻塞該線程,這就是爲什麼我需要另一個線程中的HardwareListener不會錯過信號的原因)。然後工人等待QWaitCondition(鎖定QMutex後)。

之後,硬件設備發送一個信號給HardwareListener,喚醒QWaitCondition。因此,Worker線程停止等待並完成其操作。最後,工作人員通知HMI。

問題:

不創建工人和HardwareListener線程/啓動。一切都在主線程完成,顯然,它不起作用。我不交換線程(所以沒有必要qRegisterMetaType())之間的任何特殊對象

問:

是我設計的可以接受嗎?可能還有其他方法可以做,但在我看來這是最直接的(考慮到複雜性)。


編輯:

我已經改變了我的代碼刪除QThread繼承。我使用moveToThread()方法。

現在線程正常工作。但是我有一個ActiveX錯誤:QAxBase: Error calling IDispatch member NewProject: Unknown error

看來與硬件的接口被打破了......任何想法?

Here is something interesting

You cannot move a QAxObject to another thread once it has been created. 

SOLUTION:

Here is what I have found

+0

可以看到一些代碼,也不需要移動到線程。有一些關於不從QThread繼承的帖子。 – paulm 2013-04-09 15:07:54

+0

你必須提供一些代碼..我假設你使用QThread。用QThread實現工作者和聽衆之間的溝通是什麼?你把他們移到新線程嗎?如果你繼承了QThread - 那就停止這樣做。用工人的例子閱讀文檔。 – JustAnotherCurious 2013-04-09 15:16:22

+0

你想看哪部分代碼?我已經試過不從QThread繼承,只是調用'moveToThread()'。它適用於工作人員,但不適用於HardwareListener。 你能解釋爲什麼不需要線程嗎? – Maxbester 2013-04-09 15:17:05

回答

0

Inheriting from QThread is not good design.如果你正在做的工作是計算量大,我會建議使用QThreadPool。我並不比使用異步設計更好。這意味着只有調用函數永遠不會阻塞,而是連接到通知您發生某些事情的信號。

因此,例如發送命令到硬件併發出信號,一旦硬件完成。如果硬件API不提供異步功能,那麼您不能使用線程。 QtConcurrentRun可以幫助。通常你不需要自己碰觸線程;它的地獄更容易沒有。

+0

的確,硬件API不提供異步功能。這就是要點... – Maxbester 2013-04-09 15:18:46

+0

@Maxbester是否提供幫助? – JustMaximumPower 2013-04-09 15:29:35

+0

'QtConcurrentRun'似乎並不好用。我習慣於用C和Java開發,但我對Qt編程頗爲陌生。 – Maxbester 2013-04-09 15:33:39