# 17.2 使用wxThread
如果你要在你的代碼中使用線程,首先要實現一個wxThread的派生類,并且至少要重載其虛函數Entry,這個函數包含了線程要做的主要的事情.舉例來說,比如我們要用一個單獨的線程來計算圖片中顏色的數目,下面是我們的派生類的聲明:
```
class MyThread : public wxThread
{
public:
MyThread(wxImage* image, int* count):
m_image(image), m_count(count) {}
virtual void *Entry();
private:
wxImage* m_image;
int* m_count;
};
// 一個標識符 用來在線程工作完成的時候通知應用程序.
#define ID_COUNTED_COLORS 100
```
Entry函數用來進行計算工作并且返回一個返回值(對于聯合線程(即將介紹),Wait函數將返回這個值),下面是我們的Entry函數:
```
void *MyThread::Entry()
{
(* m_count) = m_image->CountColours();
// 使用一個已知的事件來通知應用程序.
wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED,
ID_COUNTED_COLORS);
wxGetApp().AddPendingEvent(event);
return NULL;
}
```
為了簡單起見,我們沒有定義新的事件而是使用了一個已有的事件通知應用程序線程的工作已經做完了.
線程的創建
線程的創建分為兩步,首先產生一個線程的實例,然后調用線程的Create函數:
```
MyThread *thread = new MyThread();
if ( thread->Create() != wxTHREAD_NO_ERROR )
{
wxLogError(wxT("Can't create thread!"));
}
```
有兩種不同的線程,一種線程你在啟動之后就可以忘記它的存在,而另外一種,你需要等待它返回一個結果.前者我們稱為分離線程,后者稱為聯合線程. 線程的類型是通過調用wxThread的構造函數時傳遞的參數是wxTHREAD_DETACHED還是wxThrEAD_JOINABLE來決定的,聯合線程的返回值是由對其成員函數Wait的調用返回的,而對于分離線程,不可以調用Wait函數.
你不必把所有的線程都創建為聯合線程,,因為聯合線程有它不方便的地方,你必須調用聯合線程的Wait函數來等待聯合線程結束,否則系統為這個線程分配的所有的資源將不會被釋放,并且你還需要自己刪除這個線程對象(盡管這個對象只能使用一次).而分離線程則具有"點火以后就忘掉"的特性,你只需要啟動它,它將自己自己中止和釋放.
當然,這也意味者分離線程必須在堆上創建,因為它將在結束的時候調用delte(this).聯合線程既可以在棧上創建也可以在堆上創建,不同通常也都是在堆上創建的.不要創建全局的線程對象,因為他們將在他們的構造函數執行的時候分配內存,這將導致內存檢測系統出現一些問題.
指定棧大小
你可以在調用線程的Create函數的時候指定它的棧大小,默認的0代表使用操作系統默認的大小.
指定優先級
某些操作系統允許應用程序自己提供一個線程的優先級(時間片的大小),你可以通過wxThread::SetPriority函數來達到這個目的.優先級的數值在0到100之間,0為最低優先級而100為最高優先級,不過最好使用預定義的宏wxTHREAD_MIN_PRIORITY, wxTHREAD_DEFAULT_PRIORITY和wxTHREAD_MAX_ PRIORITY,他們的值分別為0,50和100.SetPriority函數應該在調用Create之后,調用Run函數之前被調用.
啟動線程
調用Create函數以后,線程還沒有開始運行,你還需要調用wxThread::Run函數來啟動線程,這個函數將會調用你自定義的Entry函數.
怎樣暫停線程以等待一個外部條件
如果線程需要等待某些事情發生,你應該避免直接使用查詢和什么事都不做這樣的循環,這會讓你的程序"忙于等待",白白浪費CPU的時間.
如果你需要等待幾秒鐘,你可以使用wxThread::Sleep函數.
如果你正在等待什么事情發生,你應該使用一種調用來阻止當前線程執行直到你收到事情已經發生的通知.例如,如果你在線程中使用了 socket,你應該阻塞在socket的系統調用上,直至socket收到數據,這就不會白白浪費CPU了,或者如果你正在等待一個聯合線程使用的數據,你可以調用Wait其函數來阻塞自己.
有時候你可能會想用線程的Pause和Resume函數來臨時將你的線程置入睡眠狀態,但是這樣做有兩個問題,首先,暫停機制不是所有的系統都支持,有些系統(尤其是POSIX標準的系統)的Pause是模擬的,線程必須調用TestDestroy并且在這個函數返回True的時候立刻中斷自己的運行.第二個問題是,調用Pause的線程有時候很難回復正常運行,因為這使得操作系統可能在任何時候中止你的線程的運行,如果你的線程正在鎖定一個信號量,很可能來不及釋放這個信號量導致出現死鎖.
因此,使用Pause和Resume并不是一個很好的設計,你應該盡可能使用信號量或者關鍵區域(參見下一小節)來重新設計你的代碼.
線程中止
正如前面我們談到的那樣,分離線程是自動結束和釋放自己的.而對于聯合線程,你可以簡單的調用wxThread::Wait函數.或者在一個GUI程序中,你可以在系統空閑事件處理函數中調用wxThread::IsAlive函數,然后僅在IsAlive返回False的時候調用 Wait函數.Wait函數是釋放聯合線程資源的唯一的方法.
你可以調用wxThread::Delete來請求刪除一個線程,不過要讓它工作正常,你需要在你的線程中周期性的調用TestDestroy函數(譯者注:根據經驗,在Windows平臺上,對于聯合線程使用這種方法好像不是一個好主意).
- 第一章 介紹
- 1.1 為什么要使用wxWidgets?
- 1.2 wxWidgets的歷史
- 1.3 wxWidgets社區
- 1.4 wxWidgets和面向對象編程
- 1.5 wxWidgets的體系結構
- 1.6 許可協議
- 第一章小結
- 第二章 開始使用
- 2.1 一個小例子
- 2.2 應用程序類
- 2.3 Frame窗口類
- 2.4 事件處理函數
- 2.5 Frame窗口的構造函數
- 2.6 完整的例子
- 2.7 wxWidgets程序一般執行過程
- 2.8 編譯和運行程序
- 第二章小結
- 第三章 事件處理
- 3.1 事件驅動編程
- 3.2 事件表和事件處理過程
- 3.3 過濾某個事件
- 3.4 掛載事件表
- 3.5 動態事件處理方法
- 3.6 窗口標識符
- 3.7 自定義事件
- 第三章小結
- 第四章 窗口的基礎知識
- 4.1 窗口解析
- 4.2 窗口類概覽
- 4.3 基礎窗口類
- 4.4 頂層窗口
- 4.5 容器窗口
- 4.6 非靜態控件
- 4.7 靜態控件
- 4.8 菜單
- 4.9 控制條
- 第四章小結
- 第五章繪畫和打印
- 5.1 理解設備上下文
- 5.2 繪畫工具
- 5.3 設備上下文中的繪畫函數
- 5.4 使用打印框架
- 5.5 使用wxGLCanvas繪制三維圖形
- 第五章小節
- 第六章處理用戶輸入
- 6.1 鼠標輸入
- 6.2 處理鍵盤事件
- 6.3 處理游戲手柄事件
- 第六章小結
- 第七章使用布局控件進行窗口布局
- 7.1 窗口布局基礎
- 7.2 窗口布局控件
- 7.3 使用布局控件進行編程
- 7.4 更多關于布局的話題
- 第七章小結
- 第八章使用標準對話框
- 8.1信息對話框
- 8.2 文件和目錄對話框
- 8.3 選擇和選項對話框
- 8.4 輸入對話框
- 8.5 打印對話框
- 第八章小結
- 第九章創建定制的對話框
- 9.1 創建定制對話框的步驟
- 9.2 一個例子:PersonalRecordDialog
- 9.3 在小型設備上調整你的對話框
- 9.4 一些更深入的話題
- 9.5 使用wxWidgets資源文件
- 第九章小結
- 第十章使用圖像編程
- 10.1 wxWidgets中圖片相關的類
- 10.2 使用wxBitmap編程
- 10.3 使用wxIcon編程
- 10.4 使用wxCursor編程
- 10.5 使用wxImage編程
- 10.6 圖片列表和圖標集
- 10.7 自定義wxWidgets提供的小圖片
- 第十章小結
- 第十一章剪貼板和拖放操作
- 11.1 數據對象
- 11.2 使用剪貼板
- 11.3 實現拖放操作
- 第十一章小結
- 第十二章高級窗口控件
- 12.1 wxTreeCtrl
- 12.2 wxListCtrl
- 12.3 wxWizard
- 12.4 wxHtmlWindow
- 12.5 wxGrid
- 12.6 wxTaskBarIcon
- 12.7 編寫自定義的控件
- 第十二章小結
- 第十三章數據結構類
- 13.1 為什么沒有使用STL?
- 13.2 字符串類型
- 13.3 wxArray
- 13.4 wxList和wxNode
- 13.5 wxHashMap
- 13.6 存儲和使用日期和時間
- 13.7 其它常用的數據類型
- 第十三章小結
- 第十四章文件和流操作
- 14.1 文件類和函數
- 14.2 流操作相關類
- 第十四章小結
- 第十五章內存管理,調試和錯誤處理
- 15.1 內存管理基礎
- 15.2 檢測內存泄漏和其它錯誤
- 15.3 構建自防御的程序
- 15.4 錯誤報告
- 15.5 提供運行期類型信息
- 15.6 使用wxModule
- 15.7 加載動態鏈接庫
- 15.8 異常處理
- 15.9 調試提示
- 第十五章小結
- 第十六章編寫國際化程序
- 16.1 國際化介紹
- 16.2 從翻譯說起
- 16.3 字符編碼和Unicode
- 16.4 數字和日期
- 16.5 其它媒介
- 16.6 一個小例子
- 第十六章小結
- 第十七章編寫多線程程序
- 17.1 什么時候使用多線程,什么時候不要使用
- 17.2 使用wxThread
- 17.3 用于線程同步的對象
- 17.4 多線程的替代方案
- 第十七章小結
- 第十八章使用wxSocket編程
- 18.1 Socket類和功能概覽
- 18.2 Socket及其基本處理介紹
- 18.3 Socket標記
- 18.4 使用Socket流
- 18.5 替代wxSocket
- 第十八章小結
- 第十九章使用文檔/視圖框架
- 19.1 文檔/視圖基礎
- 19.2 文檔/視圖框架的其它能力
- 19.3 實現Undo/Redo的策略
- 第十九章小結
- 第二十章完善你的應用程序
- 20.1 單個實例和多個實例
- 20.2 更改事件處理機制
- 20.3 降低閃爍
- 20.4 實現聯機幫助
- 20.5 解析命令行參數
- 20.6 存儲應用程序資源
- 20.7 調用別的應用程序
- 20.8 管理應用程序設置
- 20.9 應用程序安裝
- 20.10 遵循用戶界面設計規范
- 20.11 全書小結