采用CreateThread()创建多线程程序
采用CreateThread()創建多線程程序
在window環境下,Win32 提供了一系列的API函數來完成線程的創建、掛起、恢復、終結以及通信等工作:
1、主要的函數列表:
| 序號 | 函數名 | 功能 |
| 1 | CreateThread() | 創建一個新線程 |
| 2 | ExitThread() | 正常結束一個線程的執行 |
| 3 | TerminateThead() | 強制終止一個線程的執行 |
| 4 | ResumeThread() | 重啟一個線程 |
| 5 | SuspendThread() | 掛起一個線程 |
| 6 | GetExiCodeThread() | 得到一個線程的退出碼 |
| 7 | GetThreadPriority() | 得到一個線程的優先級 |
| 8 | SetThreadPriority() | 設置一個線程的優先級 |
| 9 | CloseHandle() | 關閉一個線程的句柄 |
| 10 | CreateRemoteThread() | 再另一個進程中創建一個新線程 |
| 11 | PostThreadMessage() | 發送一條消息給指定的線程 |
| 12 | GetCurrentThread() | 得到當前的線程句柄 |
| 13 | GetCurrentThreadId() | 得到當前線程的ID |
| 14 | GetThreadId() | 得到指定線程的ID |
| 15 | WaitForSingleObject() | 等待單個對象 |
| 16 | WaitForMultipleObjects() | 等待多個對象 |
關于多線程的API函數還有很多,以上只是列出了一些比較常用的函數,欲知更多函數和函數的使用方法,請參考MSDN或網絡資源,在此就不再介紹了。
2、線程函數的定義:
線程函數的規范格式定義為
DWORD ?WINAPI?ThreadProc (LPVOID lpParam);//格式不正確將無法調用成功。函數名稱沒有限制,只要符合命名規則就可以。
但我常常看到有下列的線程函數定義:
void ThreadProc ();//該格式也是可以的,但使用的時候要這樣通過
LPTHREAD_START_ROUTINE轉換,如:
(LPTHREAD_START_ROUTINE)ThreadProc
我建議還是使用規范的格式比較好,不推薦使用void ThreadProc ()格式。不信就請看看MSDN的說明吧:
Do not declare this callback function with a void return typeand cast the function pointer to LPTHREAD_START_ROUTINE when creatingthe thread. Code that does this is common, but it can crash on 64-bit Windows.
而且線程函數必須是全局函數,不能在類中聲明和定義。
3、多線程實例1:
我在此將寫一個簡單的多線程程序,用以展示多線程的功能和使用方法。該程序的主要的思想是畫3個進度條,分別以多線程和單線程方式完成,大家可以比較一下。
說明:
(1)該程序還將和單線程做對比。
(2)由于給線程的函數傳遞了多個參數,所以采用結構體的方式傳遞參數。
(3)為了演示效果,采用了比較耗時的打點處理。
主要的函數如下:
在頭文件的定義
[cpp] view plaincopy print?//實現文件中
[cpp] view plaincopy print?運行效果:
單線程測試
多線程測試
工程源碼下載地址:
http://download.csdn.net/detail/cbnotes/4857152
歡迎大家修改和指正。
注意事項:
(1)傳遞給線程執行函數的參數不能是局部變量,而且必須是參數的地址。如:
Int nOffset = 10;
CreateThread(NULL,0,ThreadProc,nOffset,0,&dwThreadID[i]);//錯誤
CreateThread(NULL,0,ThreadProc,&nOffset,0,&dwThreadID[i]);//錯誤
Int *pOffset = newint(10);
CreateThread(NULL,0,ThreadProc,pOffset,0,&dwThreadID[i]);//正確
(2)線程執行函數必須是全局函數。
(3)請大家改改下面的程序,且解釋下為什么?
這是我開始寫程序遇到的一個問題,
改寫上面的函數:只是將結構體中一個參數改為CDC指針,以便直接調用。
struct threadInfo
{
??? CDC * dc;?????? ?//畫布
??? int? nOffset;??? //偏移量
??? COLORREF clrRGB; //顏色
};
//多線程測試
void CMultiThread_1Dlg::OnBnClickedButton2()
{
??? // TODO: 在此添加控件通知處理程序代碼
??? CDC *dc = GetDC();
??? CRect rt;
??? GetClientRect(rt);
??? dc->FillSolidRect(0,0,rt.Width(),rt.Height()-70,RGB(240,240,240));//刷新背景
??? dc->TextOut(97,470,"#1");
??? dc->TextOut(297,470,"#2");
??? dc->TextOut(497,470,"#3");
??? //初始化線程的參數
??? Info[0].dc = Info[1]dc = Info[2].dc = dc;
??? Info[0].nOffset = 10;Info[1].nOffset = 210;Info[2].nOffset = 410;
??? Info[0].clrRGB = RGB(255,0,0);Info[1].clrRGB= RGB(0,255,0);Info[2].clrRGB = RGB(0,0,255);
??? //創建線程
??? for (int i = 0;i<3;i++)
??? {
?????? hThead[i] = CreateThread(NULL,0,ThreadProc,&Info[i],0,&dwThreadID[i]);
??? }
??? //ReleaseDC(dc);
}
//線程執行函數
DWORD WINAPI ThreadProc(LPVOIDlpParam)
{
??? threadInfo*Info = (threadInfo*)lpParam;
??? for (int i=0;i<460;i++)
??? {
?????? for (int j=Info->nOffset;j<Info->nOffset+190;j++)
?????? {
?????????? Info->dc->SetPixel(j,460-i,Info->clrRGB);
?????? }
??? }
??? return 0;
}
運行結果:
為什么會這樣呢?我還沒有找到答案,望大家能給我個解釋,謝謝。
===========================================================
4、多線程實例2:
該實例將演示一個簡單的多線程協同工作的例子,以供大家學習和參考。大致原理是:5個人開始比賽(比如賽跑),誰先完成比賽就結束,并統比賽時間和贏者。主線程用于界面的相關顯示,5個線程模擬5個人的行為(賽跑),另外一個線程用于檢測5個線程的運行情況,只要有人到達終點,比賽就結束并做相關的技術統計。
主要函數為:
?
MulitThread_2Dlg.h : 頭文件
//聲明線程處理函數
DWORD WINAPI ThreadProc1(LPVOIDlpParam);
DWORD WINAPI ThreadProc2(LPVOIDlpParam);
//為了傳遞多個參數,我采用結構體
struct threadInfo1
{
??? HWND hWnd;?????? //窗口句柄
??? int? nOffset;??? //偏移量
};
?
struct threadInfo2
{
??? HWND hWnd;??????????//窗口句柄
??? HANDLE *phHandle;???//偏移量
};
protected:
??? long?? m_nTime;//時間
??? HANDLE m_hThead[5];????//用于存儲線程句柄
??? HANDLE hThead;???? //用于存儲線程句柄
??? DWORD? m_dwThreadID[5];//用于存儲線程的ID
?
??? threadInfo1Info1[5];??//傳遞給線程處理函數的參數
??? threadInfo2Info2;
?
// MulitThread_2Dlg.cpp : 實現文件
//更新時間:毫秒
void CMulitThread_2Dlg::OnTimer(UINT_PTRnIDEvent)
{
??? // TODO: 在此添加消息處理程序代碼和/或調用默認值
??? m_nTime+=100;//毫秒為單位
??? CString str;
??? str.Format("時間:%.1f秒",m_nTime/1000.0);
??? GetDlgItem(IDC_STATIC2)->SetWindowText(str);
??? CDialog::OnTimer(nIDEvent);
}
?
//消息處理函數
LRESULT CMulitThread_2Dlg::OnGameOver(WPARAMwParam, LPARAMlParam)
{
??? KillTimer(1);//關閉計時器
??? if (wParam ==0)
??? {//出錯
?????? GetDlgItem(IDC_STATIC1)->SetWindowText("出錯啦!");
?????? GetDlgItem(IDC_STATIC2)->SetWindowText("---");
?????? AfxMessageBox("出錯啦!",MB_OK|MB_ICONERROR);
??? }
??? else
??? {//成功
?????? //顯示結果
?????? char *pName[] = {"張三","李四","王二","小蔡","趙干"};
?????? CStringstr;
?????? str.Format("贏者:%s",pName[lParam]);
?????? GetDlgItem(IDC_STATIC1)->SetWindowText(str);
??? }
??? //使能開始按鈕,以便可以開始下一次比賽
??? GetDlgItem(IDC_BUTTON1)->EnableWindow(TRUE);
??? return 0;
}
?
//開始比賽
void CMulitThread_2Dlg::OnBnClickedButton1()
{
??? // TODO: 在此添加控件通知處理程序代碼
??? //使能開始按鈕:無效
??? GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);
??? m_nTime =0;//初始化時間為
??? CDC *dc = GetDC();
??? CRect rt;
??? GetClientRect(rt);
??? dc->FillSolidRect(40,0,rt.Width()-49,rt.Height()-50,RGB(240,240,240));//刷新背景
??? ReleaseDC(dc);
??? //初始化線程的參數
??? Info1[0].hWnd = Info1[1].hWnd = Info1[2].hWnd = Info1[3].hWnd = Info1[4].hWnd = GetSafeHwnd();
??? Info1[0].nOffset = 0;Info1[1].nOffset = 90;Info1[2].nOffset = 180;Info1[3].nOffset = 270;Info1[4].nOffset = 360;
??? //創建線程
??? for (int i = 0;i<5;i++)
??? {??
?????? m_hThead[i] = CreateThread(NULL,0,ThreadProc1,&Info1[i],CREATE_SUSPENDED,&m_dwThreadID[i]);???
??? }
??? SetTimer(1,100,NULL);//開始計時
??? GetDlgItem(IDC_STATIC1)->SetWindowText("進行中...");
??? //開始運行
??? for (int i = 0;i<5;i++)
??? {??
?????? ResumeThread(m_hThead[i]);?
??? }
??? //開始運行監測結果線程
??? Info2.hWnd = m_hWnd;
??? Info2.phHandle = m_hThead;
??? hThead = CreateThread(NULL,0,ThreadProc2,&Info2,0,NULL);
}
?
//比賽線程
DWORD WINAPI ThreadProc1(LPVOIDlpParam)
{
??? threadInfo1*info = (threadInfo1*)lpParam;
??? CDC *dc = CWnd::FromHandle(info->hWnd)->GetDC();
??? for (int i=40;i<570;i+=2)
??? {
?????? for (int j=0;j<1000;j++)
?????? {//重復操作,以便人眼觀察
?????????? dc->Rectangle(CRect(i,info->nOffset,i+1,info->nOffset+80));
?????? }
??? }
??? DeleteObject(dc);
??? return 0;
}
?
//監視線程:誰先完成比賽就結束
DWORD WINAPI ThreadProc2(LPVOIDlpParam)
{
??? threadInfo2*info = (threadInfo2*)lpParam;
??? DWORD dwRet = 0;
??? //等待個線程中的一個完成
??? dwRet = WaitForMultipleObjects(5,info->phHandle,FALSE,INFINITE);
??? if (dwRet == WAIT_FAILED)
??? {//出錯啦
?????? ::SendMessage(info->hWnd,WM_GAMEOVER,0,0);
?????? return 0;
??? }
??? //終止各個線程
??? for (int i=0;i<5;i++)
??? {
?????? TerminateThread(info->phHandle[i],0);
??? }
??? //發送比賽結果消息
??? ::SendMessage(info->hWnd,WM_GAMEOVER,1,dwRet- WAIT_OBJECT_0);
??? return 0;
}
?
運行結果:
工程源碼下載地址:
http://download.csdn.net/detail/cbnotes/4867333
歡迎大家修改和指正。
注意事項:
1.????該程序連主線程一共7個線程。其中一個線程專門用于檢測5個比賽線程的運行結果檢測,為什么要專門開這個線程而不在主線程中進行呢?主要是WaitForMultipleObjects()函數是一個阻塞函數,如果在主線程中運行該函數,將使整個程序的界面不能操作(如:不能移動窗口等),因為一直阻塞在WaitForMultipleObjects函數處,而不能處理其它消息,不信大家可以試試。
2.????線程同步的兩個比較重要的函數為WaitForSingleObject()和WaitForMultipleObjects(),具體使用請參考MSDN。這兩個函數都是阻塞函數,一直等待授信的對象發生才返回。
3.????采用消息的方式通知主線程的運行結果,該方法比較簡單有效。一般的多線程程序都是采用主線程負責顯示,輔助線程來完成比較耗時的任務,等任務完成后再通知主線程運行結果。
?
轉載請說明出處,謝謝。
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的采用CreateThread()创建多线程程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android 仿微信朋友圈 评论,20
- 下一篇: CreateThread()与begin