那麼併發是如何實現的呢?在單核cpu上並行工作是一種錯覺,有點類似於電影中移**像的錯覺。對於程序來說,在很短的時間後中斷處理器在乙個程序上的工作就會產生錯覺。然後處理器繼續下乙個程序。為了在程序之間進行切換,當前程式計數器被儲存,下乙個處理器的程式計數器被載入。這還不夠,因為需要對暫存器、特定體系結構和特定於作業系統的資料進行同樣的處理。
正如乙個cpu可以為兩個或多個程序提供動力一樣,也可以讓cpu執行在單個程序的兩個不同**段上。當乙個程序啟動時,它總是執行乙個**段,因此該程序有乙個執行緒。但是,程式可能決定啟動第二個執行緒。然後,在乙個程序中同時處理兩個不同的**序列。併發是通過反覆儲存程式計數器和暫存器,然後載入下乙個執行緒的程式計數器和暫存器,在單核cpu上實現的。在活動執行緒之間迴圈不需要來自程式的協作。當切換到下乙個執行緒時,執行緒可能處於任何狀態。
當前cpu設計的趨勢是擁有多個核心。典型的單執行緒應用程式只能使用乙個核心。但是,具有多個執行緒的程式可以分配給多個核,從而使事情以真正併發的方式發生。因此,將工作分配到多個執行緒可以使程式在多核cpu上執行得更快,因為可以使用額外的核。
如前所述,每個程式在啟動時都有乙個執行緒。這個執行緒稱為「主線程」(在qt應用程式中也稱為「gui執行緒」)。qt gui必須在這個執行緒中執行。所有小部件和幾個相關類,例如qpixmap,都不能在輔助線程中工作。輔助線程通常被稱為「工作執行緒」,因為它用於從主線程分擔處理工作。
每個執行緒都有自己的棧,這意味著每個執行緒都有自己的呼叫歷史和本地變數。與程序不同,執行緒共享相同的位址空間。下圖顯示了執行緒的構建塊在記憶體中的位置。非活動執行緒的程式計數器和暫存器通常儲存在核心空間中。每個執行緒都有乙個共享的**副本和乙個單獨的棧。
如果兩個執行緒有乙個指向同一物件的指標,那麼兩個執行緒可能會同時訪問該物件,這可能會破壞物件的完整性。很容易想象,當同一物件的兩個方法同時執行時,可能會出現許多錯誤。
有時需要從不同的執行緒訪問乙個物件;例如,當生存在不同執行緒中的物件需要通訊時。由於執行緒使用相同的位址空間,所以執行緒交換資料要比程序更容易更快。資料不必序列化和複製。傳遞指標是可能的,但必須嚴格協調哪個執行緒接觸哪個物件。必須防止在乙個物件上同時執行操作。有幾種方法可以實現這一點,下面描述了其中一些方法。
線程基本上有兩種用例:
開發人員在使用執行緒時需要非常小心。 啟動其他執行緒很容易,但是很難確保所有共享資料保持一致。 問題通常很難發現,因為它們可能僅偶爾出現一次或僅在特定的硬體配置上出現。 在建立執行緒來解決某些問題之前,應考慮可能的替代方法。
alternative
簡介qeventloop::processevents()
在耗時的計算過程中重複呼叫qeventloop :: processevents() 可防止gui阻塞。 但是,此解決方案不能很好地擴充套件,因為根據硬體的不同,對processevents() 的呼叫可能發生的次數過多或不足。
qtimer
有時可以使用計時器方便地完成後台處理,以安排將來某個時刻執行插槽。 沒有更多事件要處理時,間隔為0的計時器將超時。
qsocketnotifier qnetworkaccessmanager qiodevice::readyread()
這是具有乙個或多個執行緒的替代方法,每個執行緒在慢速網路連線上都具有阻止讀取的功能。 只要可以快速執行響應大量網路資料的計算,這種響應式設計就比執行緒中的同步等待更好。 響應式設計比執行緒設計更不容易出錯並且更節能。 在許多情況下,還可以提高效能。
通常,建議僅使用安全且經過測試的路徑,並避免引入臨時執行緒概念。 qtconcurrent模組提供了乙個簡單的介面,用於將工作分配到所有處理器核心。 執行緒**完全隱藏在qtconcurrent框架中,因此您不必關心細節。 但是,當需要與正在執行的執行緒進行通訊時,不能使用qtconcurrent,並且不應將其用於處理阻塞操作。
以下各節描述了qobjects如何與執行緒互動,程式如何安全地從多個執行緒訪問資料以及非同步執行如何在不阻塞執行緒的情況下產生結果。
如上所述,開發人員在從其他執行緒呼叫物件方法時必須始終小心。qobject的執行緒親和性不會改變這種情況。qt文件將幾個方法標記為執行緒安全的。postevent()是乙個值得注意的例子。執行緒安全的方法可以從不同的執行緒同時呼叫。
在通常沒有併發訪問方法的情況下,在併發訪問發生之前,呼叫其他執行緒中物件的非執行緒安全方法可能要工作數千次,從而導致意外行為。編寫測試**並不能完全確保執行緒的正確性,但它仍然很重要。在linux上,valgrind和helgrind可以幫助檢測線程錯誤。
在編寫多執行緒應用程式時,必須特別注意避免資料損壞。有關如何安全使用執行緒的討論,請參閱同步執行緒(synchronizing threads)。
獲得工作執行緒結果的一種方法是等待執行緒終止。然而,在許多情況下,阻塞等待是不可接受的。阻塞等待的替代方法是使用已發布的事件或排隊的訊號和槽非同步結果交付。這將產生一定的開銷,因為操作的結果不會出現在下乙個源**行上,而是出現在原始檔中其他位置的槽中。qt開發人員習慣於使用這種非同步行為,因為它與gui應用程式中使用的事件驅動程式設計非常相似。
qt提供了幾個使用執行緒的示例。有關簡單示例,請參閱qthread和qthreadpool的類。有關更高階的示例,請參見執行緒和併發程式設計示例頁面(threading and concurrent programming examples)。
執行緒是乙個非常複雜的主題。qt提供的執行緒模擬我們在本教程中介紹的要多。以下材料可以幫助你更深入地了解這個主題:
Qt執行緒基礎知識
那麼併發性是如何實現的呢?在單核cpu上並行工作是一種錯覺,有點類似於電影中移 像的錯覺。對於程序,這種錯覺是通過在很短的時間後中斷處理器在乙個程序上的工作而產生的。然後處理器轉到下一道工序。為了在程序之間切換,儲存當前的程式計數器並載入下乙個處理器的程式計數器。這是不夠的,因為同樣需要對暫存器 某...
Qt 執行緒 07 Qt模組中的執行緒支援 官翻
此外,qsqldrivers使用的第三方庫可以對在多執行緒程式中使用sql模組施加進一步的限制。有關更多資訊,請參閱資料庫客戶端手冊 任意數量的執行緒可以在任何給定的時間進行繪製,但是在乙個給定的繪製裝置上只有乙個執行緒一次可以進行繪製。換句話說,如果每個執行緒都繪製到單獨的qimages上,那麼兩...
多執行緒基礎知識
建立乙個序列佇列,該佇列中從方的都是要依次執行的任務,dispatch queue serial 表示序列佇列的標示 dispatch queue t serialqueue dispatch queue create serial dispatch queue serial 建立乙個並行佇列,並行...