Windows 執行緒漫談 介面執行緒和工作者執行緒

2021-04-27 19:28:23 字數 3759 閱讀 4899

每個系統都有執行緒,而執行緒的最重要的作用就是並行處理,提高軟體的併發率。針對介面來說,還能提高介面的響應力。

執行緒分為介面執行緒和工作者執行緒,介面實際就是乙個執行緒畫出來的東西,這個執行緒維護乙個「訊息佇列」,「訊息佇列」也是介面執行緒和工作者執行緒的最大區別,這個詞應該進到你的腦子裡,根深蒂固的!

如果在介面執行緒的某個地方停住,這說明它處理不了視窗訊息了,所以有時候我們就會看到整個介面無響應了。這種問題後面會提供乙個叫 waitforobjectex 的函式來解決,我們後面再談。

執行緒首先就是它的建立,建立是用下面這個函式:createthread; 具體的引數我不說了,自己查msdn。其中的 thread1 是執行緒函式。執行緒函式是乙個全域性函式,如下:

dword winapi thread1(lpvoid lpparam)

return 0;}

// 下面這一句是建立執行緒

createthread(null, 0, thread1, 0, 0, null);

當然我們不能讓乙個執行緒自生自滅,那樣有可能在你退出程式的時候出現一些莫名其妙的問題,或者丟失一些資料,或者給你彈乙個崩潰的對話方塊等等。。。

所以我們就要對這個執行緒進行管理,首先就是讓它退出。

dword winapi thread1(lpvoid lpparam)

return 0;}

然後在需要它退出的時候把g_bexitthread設為true,表示,喂,兄弟,你該退出了。

當然我們還要知道它是否成功退出了,因為執行緒控制代碼是乙個核心物件,所以我們就要用到windows的waitforsingleobject來等待了。建立的時候和等待它退出的**就要改變了,多了乙個 handle g_htrd的變數:

// 建立

g_bexitthread = false;

g_htrd = createthread(null, 0, thread1, 0, 0, null);

// 等待執行緒結束

g_bexitthread = true;

if(g_htrd != null)

else

closehandle(g_htrd);

g_htrd = null;}

上面說了在介面執行緒裡等待別的執行緒結束,也就是使用 waitforsingleobject 的時候會阻塞整個視窗訊息的處理,所以我們如果在介面執行緒裡要等待別的核心物件時,我們要採用這種「等一下,處理一下介面訊息」的方法。我已經寫好了乙個 waitforobjectex 的函式,如下:

// 此函式只能用於介面執行緒

static dword waitforobjectex( handle hhandle, dword dwmilliseconds )

if (bret == -1)

else}

return iwaitret;}

很多時候,我們不想把執行緒作為乙個全域性函式來使用,所以這個時候我們把執行緒作為乙個類的靜態成員物件來寫。當然也不能少了剛才的兩個變數:退出標誌和執行緒控制代碼。(設這個類是ctestthreaddlg)

// h 檔案 

bool m_bexitthread;

handle m_htrd;

static dword winapi thread1(lpvoid lpparam);

// cpp檔案,建立的時候把 this 指標傳進去,因為類靜態成員函式不能訪問類的非靜態成員,沒有this指標

//(c++的知識點)

m_bexitthread = false;

m_htrd = createthread(null, 0, thread1, this, 0, null);

執行緒函式變成了:

dword winapi ctestthreaddlg::thread1(lpvoid lpparam)

return 0;}

當有幾個執行緒一起跑的時候,我們就要注意執行緒的同步問題了,執行緒的同步一般來說,是在多個執行緒共用了資源的時候。比如兩個執行緒都用到了同乙個vector,都對vector進行插入操作,不幸的是,vector不是執行緒安全的,這個時候程式就會崩潰,所以我們就要對vector這個資源做同步,同步的意思是「我訪問的時候,你等待」。程式大致如下:

dword winapi ctestthreaddlg::thread1(lpvoid lpparam)

return 0;}

dword winapi ctestthreaddlg::thread2(lpvoid lpparam)

return 0;}

m_csforvec 是乙個ccriticalsection變數,這個同步物件和其他的同步變數(事件、訊號量、互斥區等)有一些不一樣,例如只能在同乙個程序的執行緒間訪問、在作業系統的使用者態訪問,其他的必須進入核心態。所以這樣導致了這種關鍵區的核心物件的速度要比其他的快100倍左右。。。

上面已經說了執行緒的建立、管理(退出執行緒、等待執行緒)、同步等,那我們發現了什麼共性呢?作為乙個程式設計師,我們要很敏感的發現這些**上的共性,這是我們設計**的主要前提。

首先我們發現上面的執行緒都有兩個變數: 

bool m_bexitthread;  // 讓執行緒退出的標誌

handle m_htrd;  // 執行緒控制代碼

另外我們waitforsingleobject 的時候不能無限等待,所以要多乙個 dword m_dwwaittimeout;

由於我想把執行緒啟動和結束封裝起來,所以我設計了這幾個介面:

bool start(lpvoid lpparam);  //  啟動執行緒,執行緒所需要的引數從這裡傳進

bool end(); // 結束執行緒

virtual void run(); // 重寫run函式

所以整個的執行緒封裝成以下的類:

// mythread.h

#ifndef my_thread_h

#define my_thread_h

class cmythread;

#endif

// mythread.cpp

#include "stdafx.h"

#include "mythread.h"

/// cmythread

cmythread::cmythread()

cmythread::~cmythread()

bool cmythread::start(lpvoid lpparam)

bool cmythread::end()

else

closehandle(m_htrd);

m_htrd = null;

}return true;}

dword winapi cmythread::thread(lpvoid lpparam)

return 0;}

void cmythread::runonceend()

void cmythread::run()

我們需要寫我們自己的執行緒的時候就過載一下這個run函式

// 派生出乙個類

class cmythread1 : public cmythread

;// 改寫run函式

void cmythread1::run()

然後我們之前的兩個執行緒的使用就變成了下面的形式:

cmythread1 g_t1, g_t2, g_t3;

void ctestthreaddlg::onbutton3()

void ctestthreaddlg::onbutton4()

只需要以下幾步:

1、派生自己的執行緒類

2、過載run函式

3、呼叫start啟動執行緒

4、呼叫end結束執行緒

Windows執行緒漫談介面執行緒和工作者執行緒

每個系統都有執行緒,而執行緒的最重要的作用就是並行處理,提高軟體的併發率。針對介面來說,還能提高介面的響應力。執行緒分為介面執行緒和工作者執行緒,介面實際就是乙個執行緒畫出來的東西,這個執行緒維護乙個 訊息佇列 訊息佇列 也是介面執行緒和工作者執行緒的最大區別,這個詞應該進到你的腦子裡,根深蒂固的!...

建立使用者介面執行緒

建立使用者介面執行緒 本人節選自 21天學通c 一書 說明 中使用了declare dyncreate巨集,使用該巨集表明mythread類具有動態建立的能力。使用declare message map巨集表明具有訊息對映,可以處理命令訊息。再開啟mythread類的實現檔案 mythread.cp...

使用者介面執行緒AfxBeginThread的使用

使用者介面執行緒在執行時會有乙個視窗介面和與其相對應的視窗函式,所以它可以通過響應訊息來和使用者進行互動。afxbeginthread 函式原型如下 cwinthread afxbeginthread cruntimeclass pthreadclass,從cwinthread派生的runtime ...