VC官方多執行緒例程的分析

2021-04-02 10:34:54 字數 3838 閱讀 4743

我們來分析一下visual c++提供的有關多執行緒的例程,看看一些多執行緒元素的典型用法。讀者可執行這些例程,以獲得多執行緒執行的直觀效果。

(1)mtrecalc

例程mtrecalc的功能是在乙個視窗中完成簡單的加法運算,使用者可輸入加數和被加數,例程完成兩數相加。使用者可通過選單選擇單執行緒或用輔助線程來做加法運算。如果選擇輔助線程進行加法運算,則在進行運算的過程中,使用者可繼續進行一些介面操作,如訪問選單、編輯數值等,甚至可以中止輔助運算執行緒。為了使其效果更加明顯,例程在計算過程中使用了迴圈和延時,模擬乙個複雜的計算過程。

在程式的crecalcdoc類中,用到了乙個執行緒物件和四個同步事件物件:

cwinthread* m_precalcworkerthread;

handle m_heventstartrecalc;

handle m_heventrecalcdone;

handle m_heventkillrecalcthread;

handle m_heventrecalcthreadkilled;

void crecalcdoc::updateint1andint2(int n1, int n2, bool bforcerecalc);

在多執行緒的情況下,還會呼叫下面的crecalcdoc::recalcinsecondthread函式:

void crecalcdoc::recalcinsecondthread()

m_recalcthreadinfo.m_nint1 = m_nint1;

m_recalcthreadinfo.m_nint2 = m_nint2;

position pos = getfirstviewposition();

cview* pview = getnextview(pos);

m_recalcthreadinfo.m_hwndnotifyrecalcdone = pview->m_hwnd;

m_recalcthreadinfo.m_hwndnotifyprogress = afxgetmainwnd()->m_hwnd;

m_recalcthreadinfo.m_nrecalcspeedseconds = m_nrecalcspeedseconds;

setevent(m_heventrecalcdone);

resetevent(m_heventkillrecalcthread);

resetevent(m_heventrecalcthreadkilled);

setevent(m_heventstartrecalc);

} 應用程式呼叫afxbeginthread啟動了執行緒,把m_recalcthreadinfo作為引數傳給執行緒函式。函式中最後的四行語句設定了四個事件物件的狀態,這些事件物件在文件類的建構函式中建立。下面是實際的運算執行緒函式:

uint recalcthreadproc(lpvoid pparam)

if (!brecalccompleted)

setevent(precalcinfo->m_heventrecalcthreadkilled);

return 0;

} bool slowadd(int nint1, int nint2, int& nresult, crecalcthreadinfo* pinfo, int nseconds,hwnd hwndnotifyprogress)

return false; // terminate this recalculation

} if (pinfo != null

&&waitforsingleobject(pinfo->m_heventstartrecalc, 0) == wait_object_0)

// update the progress indicator

sleep(nseconds * 50);

} // update the progress indicator

} nresult = nint1 + nint2;

return true;

} 上面的**充分顯示了幾個事件物件的用法。當執行緒剛啟動時,先等待m_heventstartrecalc的狀態為允許,然後檢查m_heventkillrecalcthread事件物件的狀態。注意這兩個等待函式呼叫的第二個引數的區別:在進入計算函式之前,設定m_heventrecalcdone事件為不允許狀態;待計算結束後,將其設定為允許狀態。在計算函式的處理過程中,迴圈檢查事件m_heventkillrecalcthread和m_heventstartrecalc的狀態,如果m_heventkillrecalcthread事件允許,則退出執行緒,中止計算。

當計算執行緒在計算時,主線程可繼續接受使用者輸入(包括選單選擇)。使用者可通過選單項中止計算執行緒。中止執行緒的處理比較簡單,**如下:

void crecalcdoc::onkillworkerthread()

通過設定m_heventkillrecalcthread事件物件,計算執行緒的迴圈就會檢測到該事件的狀態,最終引起執行緒的退出。注意:執行緒的中止因函式的退出而自然中止,而沒有用強行辦法中止,這樣可保證系統的安全性。另外,在程式的很多地方使用了postmessage來更新計算進度的指示,使用postmessage函式傳送訊息可立即返回,無需等待,這樣就避免了阻塞,比較符合多執行緒程式設計的思想,建議讀者使用這種訊息傳送方法。尤其是在多個ui執行緒程式設計時,用這種方法更合適。

(2)m***i

例程m***i是乙個mdi應用,每乙個子視窗是乙個使用者介面執行緒,子視窗裡有乙個來回彈跳的小球,小球的運動由計時器控制,此處不加以討論。下面,我們來看看ui執行緒的建立過程以及它與mdi的結合。

通過選單命令new bounce,可在主框架視窗類中響應選單命令,函式**如下:

void cmainframe::onbounce()

函式呼叫子框架視窗的建立函式,**如下:

bool cbouncemdichildwnd::create(lpctstr sztitle, long style, const rect& rect, cmdiframewnd* parent)

上述函式生成乙個新的ui執行緒物件pbouncethread,並呼叫createthread函式建立執行緒。至此,執行緒已被建立,但還需要做初始化工作,如下面的函式initinstance所示:

int cbouncethread::initinstance()

注意:這裡,將m_pmainwnd設定為新建立的cbouncewnd視窗是必需的。只有這樣設定了,才能保證當cbouncewnd視窗被刪除時,執行緒會被自動刪除。

(3)mutexes

例程mutexes是乙個對話方塊程式。除主線程外,還有兩個執行緒:乙個用於計數,乙個用於顯示。在本例中,這兩個執行緒都是從cwinthread派生出來的,但並不用於訊息迴圈處理,派生類過載了run函式,用於完成其計數和顯示的任務。

在對話方塊類中使用了乙個內嵌的cmutex物件。對話方塊初始化時建立兩個執行緒,並設定相應的引數,然後啟動執行兩個執行緒。

當使用者設定了對話方塊的同步檢查框標記後,兩個執行緒的同步處理有效。在計數執行緒的迴圈中,先呼叫csinglelock::lock函式,然後進行計數修改,最後呼叫csinglelock::unlock函式。注意:這裡的csinglelock物件根據主對話方塊的cmutex物件產生。在顯示執行緒的迴圈中,先呼叫csinglelock::lock函式,然後取到計數值,最後呼叫csinglelock::unlock函式。注意:這裡的csinglelock物件也是由主對話方塊的cmutex物件產生。類似這種情況:乙個執行緒要讀取資料,另乙個執行緒要修改資料,這是我們在處理多執行緒問題時碰到的最典型的情況。此處採用的方法也具有典型意義。源**可通過檢視例程或通過聯機幫助來獲取。

這個例程的具體實現參見:http://www.vchome.net/tech/thread_2.htm

C 多執行緒例程

lock guard include include 執行緒 include 鎖 using namespace std void fun 1 宣告分支執行緒函式fun 1 void fun 2 宣告分支執行緒函式fun 2 unsigned int counter 0 定義變數counter,通過...

VC 多執行緒

1.createthread函式 引數說明 2.createmutex handle createmutex lpsecurity attributeslpmutexattributes,sd boolbinitialowner,initial owner lpctstrlpname object ...

VC多執行緒的同步

1.利用事件物件同步 事件分為 人工重置的事件物件和自動重置的事件物件。人工重置的事件物件 收到通知,等待的所以執行緒變為可排程執行緒。自動重置的事件物件 收到通知,等待的所以執行緒只有乙個變為可排程。同時作業系統會將事件物件設定為無訊號狀態。為了實現執行緒間的同步,不應該使用人工重置的事件物件,而...