♥ 學習筆記Learning 程式語言 Coding

[程式] QT-Connection 機制-多執行緒

為了要解決多執行緒(Multi-threads)操作圖形介面(GUI)的問題,所以,我們從QT最特別的slot與signal機制下手。其中,如果需要跨執行緒(Cross Thread),Qt::QueuedConnection或許是我們可以選擇的解法之一。

大致的概念是這樣的。

只有主執行緒(main thread)可以操控GUI介面控制;如果使用其他的執行緒(the other threads)進行介面的操作,可能看起來正常,但是在某一天軟體會出現無法預期的錯誤或終止(Crash),這也就是編譯器(compiler)一再的警告不安全的使用(unsafe used)的原因。

在做了小小的測試之後,我們發現QT 4.7.4的版本,即使跨執行緒使用圖形介面操作,仍然可以正常顯現,即使有不少論壇提出他們在之後所遇到的非預期終止的問題;而在QT 4.8.1的版本中,當我們使用跨執行緒的方式直接操作圖形介面,圖形則是直接消失,無法顯示在介面上;因此我們不得不,也必須去修正這個警告。

以下是來自QT助手(Qt Assistant)給的提示,關於各式各樣的Connection用法。
而蕾咪將保留原文,避免誤譯,並且做一點簡單的中文翻譯,讓大家更容易理解用法。

Constant Value Description
Qt::AutoConnection 0 (default) Same as DirectConnection, if the emitter and receiver are in the same thread.
Same as QueuedConnection, if the emitter and receiver are in different threads.如果傳送與接收來自同一個執行緒(thread),用法與DirectConnection相同;如果傳送與接收來自不同的執行緒(Cross-thread),使用方法則與QueuedConnection相同。
Qt::DirectConnection 1 The slot is invoked immediately, when the signal is emitted.當訊息(Signal)傳送時,訊息槽(Slot)會直接被呼叫。
Qt::QueuedConnection 2 The slot is invoked when control returns to the event loop of the receiver’s thread. The slot is executed in the receiver’s thread.當控制值回傳(control return)給接收者執行緒的事件迴圈(event loop),訊息槽(slot)將會被呼叫。訊息槽在接收者執行緒中執行。
Qt::BlockingQueuedConnection 4 Same as QueuedConnection, except the current thread blocks until the slot returns. This connection type should only be used where the emitter and receiver are in different threads. Note:Violating this rule can cause your application to deadlock.與QueuedConnection相同,值到slots回傳值給現在的執行緒,才會繼續往下執行。這個類型只限定在傳送與接收都在不同的執行緒時。記住:違反這一點可能會導致應用程式陷入死結(deadlock)。
Qt::UniqueConnection 0x80 Same as AutoConnection, but the connection is made only if it does not duplicate an existing connection. i.e., if the same signal is already connected to the same slot for the same pair of objects, then the connection will fail. This connection type was introduced in Qt 4.6.與AutoConnection相同,但是僅限於不會重複存在的連結。也就是說,如果有同一個訊號(Signal)已經連接相同的訊息槽(Slot)在同一個物件上,那麼這個連結將會失敗。這個連結類型將在Qt 4.6上介紹。
Qt::AutoCompatConnection 3 The default type when Qt 3 support is enabled. Same as AutoConnection but will also cause warnings to be output in certain situations. See Compatibility Signals and Slots for further information.這個預設的類型在Qt3是被支援的。與AutoConnection相同,但是當在同一種情形時,也會導致警告,可以從Compatibility Signals and Slots參考更多的資訊。

多執行緒(Mult threads)是一個對於大多數初學者來說,有點抽象的概念。

有一個在學作業系統時,我很喜歡的清楚例子。
這裡簡單的帶過為何在多執行緒時,我們需要使用QMutex或QMutexlock。

想想看,在排隊上廁所的時候,廁所只有一個,而許多人都想要上廁所;這種時候,難免會產生搶廁所的情形,或是一群人擠在同一間廁所搶馬桶,這樣的情形會變得一團亂,而且有點髒(笑)。因此,在人類的世界裡面,我們知道要輪流或排隊上廁所,而且上廁所時,記得要鎖門,不然上到一半門被打開,這就尷尬了!(= ” =)|||||||

所以,在電腦的世界裡面,當一群函式或執行緒(想上廁所的人)想要搶著存取同一份變數資料或資源(廁所)時,就會發生這種都撞在一起的情形,於是會產生各種非預期的狀況與錯誤的狀況;當然不做適當的保護並不代表一定會出錯,但是總有一天會;就像你總是上偏僻的廁所都不鎖門,可能一兩年都沒人剛好打開,隨你高興怎麼用,可是可能有一天不幸的是剛好有路人經過,不知道你在裡面上廁所,就打開了你的門,然後…。

因此,QMutex的機制是在提供你鎖門的功能,你在用廁所的時候,直到你用完之前,誰都不可以隨便闖進來。
也就是說,當你在函式內存取某些變數時,在你使用完這些變數之前,誰都不可以隨意修改那些變數的值。

那單一執行緒呢?親愛的,你住在你的單人套房,除非你允許,否則是不會有人可以跟你搶廁所的。

 

因此,當我們需要跨執行緒做溝通時,在QT裡面提供了一個「排隊」的機制。
Queue可以想做是一個正在排隊的隊伍,所以「先進先出」,輪流處理要做的事情。

而Connection呢?其實可以想像成(A告訴B)要做甚麼?connection(A,SIGNAL(), B, SLOT()),這就是我前文在視覺化介面提到的,你丟我接的概念;connection(小明, SIGNAL(丟球), 老王, SLOT(接球))。

 

先寫到這裡,統整一下最近理解到的東西。
希望問題能正確被解決,待續囉!^^
歡迎交流心得~感恩~

 

參考資料:

[1] QT源码之Qt信号槽机制与事件机制的联系 http://mobile.51cto.com/symbian-270997.htm

[2] Difference between Qt::QueuedConnection vs Qt::BlockingQueuedConnection http://www.qtcentre.org/threads/25450-Difference-between-Qt-QueuedConnection-vs-Qt-BlockingQueuedConnection

[3] Thread Support in Qt http://doc.qt.digia.com/4.4/threads.html#painting-in-threads

About the author

蕾咪

蕾咪,來自台東,卻不定期旅居歐洲的工程師女孩,身兼作家、部落客、創業家等多重身份。畢業於台大電子所,曾在義大利商與美商擔任研發工程師;走訪世界後,發現對台灣有段割捨不了的愛,讓我們一起努力成為想要的自己吧!:) 合作邀稿請聯繫:ramihaha@gmail.com

Leave a Comment