日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

采用CreateThread()创建多线程程序

發(fā)布時間:2025/3/12 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 采用CreateThread()创建多线程程序 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

采用CreateThread()創(chuàng)建多線程程序

在window環(huán)境下,Win32 提供了一系列的API函數來完成線程的創(chuàng)建、掛起、恢復、終結以及通信等工作:

1、主要的函數列表:

序號

函數名

功能

1

CreateThread()

創(chuàng)建一個新線程

2

ExitThread()

正常結束一個線程的執(zhí)行

3

TerminateThead()

強制終止一個線程的執(zhí)行

4

ResumeThread()

重啟一個線程

5

SuspendThread()

掛起一個線程

6

GetExiCodeThread()

得到一個線程的退出碼

7

GetThreadPriority()

得到一個線程的優(yōu)先級

8

SetThreadPriority()

設置一個線程的優(yōu)先級

9

CloseHandle()

關閉一個線程的句柄

10

CreateRemoteThread()

再另一個進程中創(chuàng)建一個新線程

11

PostThreadMessage()

發(fā)送一條消息給指定的線程

12

GetCurrentThread()

得到當前的線程句柄

13

GetCurrentThreadId()

得到當前線程的ID

14

GetThreadId()

得到指定線程的ID

15

WaitForSingleObject()

等待單個對象

16

WaitForMultipleObjects()

等待多個對象

關于多線程的API函數還有很多,以上只是列出了一些比較常用的函數,欲知更多函數和函數的使用方法,請參考MSDN或網絡資源,在此就不再介紹了。

2、線程函數的定義:

線程函數的規(guī)范格式定義為

DWORD ?WINAPI?ThreadProc (LPVOID lpParam);//格式不正確將無法調用成功。函數名稱沒有限制,只要符合命名規(guī)則就可以。

但我常常看到有下列的線程函數定義:

void ThreadProc ();//該格式也是可以的,但使用的時候要這樣通過

LPTHREAD_START_ROUTINE轉換,如:

(LPTHREAD_START_ROUTINE)ThreadProc

我建議還是使用規(guī)范的格式比較好,不推薦使用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?
  • //線程函數聲明??
  • DWORD?WINAPI?ThreadProc(LPVOIDlpParam);??
  • //為了傳遞多個參數,我采用結構體??
  • struct?threadInfo??
  • {??
  • ????HWND?hWnd;???????//窗口句柄??
  • ????int??nOffset;????//偏移量??
  • ????COLORREF?clrRGB;?//顏色??
  • };??
  • ???
  • protected:??
  • HANDLE?hThead[3];????//用于存儲線程句柄??
  • ????DWORD??dwThreadID[3];//用于存儲線程的ID??
  • ??threadInfo?Info[3];???//傳遞給線程處理函數的參數??
  • //線程函數聲明 DWORD WINAPI ThreadProc(LPVOIDlpParam); //為了傳遞多個參數,我采用結構體 struct threadInfo {HWND hWnd; //窗口句柄int nOffset; //偏移量COLORREF clrRGB; //顏色 };protected: HANDLE hThead[3]; //用于存儲線程句柄DWORD dwThreadID[3];//用于存儲線程的IDthreadInfo Info[3]; //傳遞給線程處理函數的參數

    //實現文件中

    [cpp] view plaincopy print?
  • //單線程測試??
  • void?CMultiThread_1Dlg::OnBnClickedButton1()??
  • {??
  • ????//?TODO:?在此添加控件通知處理程序代碼??
  • ????//使能按鈕??
  • ????GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);??
  • ????GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);??
  • ????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");??
  • ????//#1??
  • ????for?(int?i=0;i<460;i++)??
  • ????{??
  • ???????for?(int?j?=10?;j<200;j++)??
  • ???????{??
  • ???????????dc->SetPixel(j,460-i,RGB(255,0,0));??
  • ???????}??
  • ????}??
  • ????//#2??
  • ????for?(int?i=0;i<460;i++)??
  • ????{??
  • ???????for?(int?j?=210?;j<400;j++)??
  • ????????{??
  • ???????????dc->SetPixel(j,460-i,RGB(0,255,0));??
  • ???????}??
  • ????}??
  • ????//#3??
  • ????for?(int?i=0;i<460;i++)??
  • ????{??
  • ???????for?(int?j?=410?;j<600;j++)??
  • ???????{??
  • ???????????dc->SetPixel(j,460-i,RGB(0,0,255));??
  • ???????}??
  • ????}??
  • ????ReleaseDC(dc);??
  • ????//使能按鈕??
  • ????GetDlgItem(IDC_BUTTON1)->EnableWindow(TRUE);??
  • ????GetDlgItem(IDC_BUTTON2)->EnableWindow(TRUE);??
  • }??
  • ???
  • //多線程測試??
  • 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].hWnd?=?Info[1].hWnd?=?Info[2].hWnd?=?GetSafeHwnd();??
  • ????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);??
  • ????//創(chuàng)建線程??
  • ????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;??
  • ????CDC?*dc?=?CWnd::FromHandle(Info->hWnd)->GetDC();??
  • ????for?(int?i=0;i<460;i++)??
  • ????{??
  • ???????for?(int?j=Info->nOffset;j<Info->nOffset+190;j++)??
  • ???????{??
  • ???????????dc->SetPixel(j,460-i,Info->clrRGB);??
  • ???????}??
  • ????}??
  • ????DeleteObject(dc);??
  • ????return?0;??
  • }??
  • //單線程測試 void CMultiThread_1Dlg::OnBnClickedButton1() {// TODO: 在此添加控件通知處理程序代碼//使能按鈕GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);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");//#1for (int i=0;i<460;i++){for (int j =10 ;j<200;j++){dc->SetPixel(j,460-i,RGB(255,0,0));}}//#2for (int i=0;i<460;i++){for (int j =210 ;j<400;j++){dc->SetPixel(j,460-i,RGB(0,255,0));}}//#3for (int i=0;i<460;i++){for (int j =410 ;j<600;j++){dc->SetPixel(j,460-i,RGB(0,0,255));}}ReleaseDC(dc);//使能按鈕GetDlgItem(IDC_BUTTON1)->EnableWindow(TRUE);GetDlgItem(IDC_BUTTON2)->EnableWindow(TRUE); }//多線程測試 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].hWnd = Info[1].hWnd = Info[2].hWnd = GetSafeHwnd();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);//創(chuàng)建線程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;CDC *dc = CWnd::FromHandle(Info->hWnd)->GetDC();for (int i=0;i<460;i++){for (int j=Info->nOffset;j<Info->nOffset+190;j++){dc->SetPixel(j,460-i,Info->clrRGB);}}DeleteObject(dc);return 0; }

    運行效果:

    單線程測試


    多線程測試

    工程源碼下載地址:

    http://download.csdn.net/detail/cbnotes/4857152

    歡迎大家修改和指正。

    注意事項:

    (1)傳遞給線程執(zhí)行函數的參數不能是局部變量,而且必須是參數的地址。如:

    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)線程執(zhí)行函數必須是全局函數。

    (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);

    ??? //創(chuàng)建線程

    ??? for (int i = 0;i<3;i++)

    ??? {

    ?????? hThead[i] = CreateThread(NULL,0,ThreadProc,&Info[i],0,&dwThreadID[i]);

    ??? }

    ??? //ReleaseDC(dc);

    }

    //線程執(zhí)行函數

    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:

    該實例將演示一個簡單的多線程協(xié)同工作的例子,以供大家學習和參考。大致原理是:5個人開始比賽(比如賽跑),誰先完成比賽就結束,并統(tǒng)比賽時間和贏者。主線程用于界面的相關顯示,5個線程模擬5個人的行為(賽跑),另外一個線程用于檢測5個線程的運行情況,只要有人到達終點,比賽就結束并做相關的技術統(tǒng)計。

    主要函數為:

    ?

    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;

    ??? //創(chuàng)建線程

    ??? 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]);?

    ??? }

    ??? //開始運行監(jiān)測結果線程

    ??? 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;

    }

    ?

    //監(jiān)視線程:誰先完成比賽就結束

    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);

    ??? }

    ??? //發(fā)送比賽結果消息

    ??? ::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。這兩個函數都是阻塞函數,一直等待授信的對象發(fā)生才返回。

    3.????采用消息的方式通知主線程的運行結果,該方法比較簡單有效。一般的多線程程序都是采用主線程負責顯示,輔助線程來完成比較耗時的任務,等任務完成后再通知主線程運行結果。

    ?

    轉載請說明出處,謝謝。

    與50位技術專家面對面20年技術見證,附贈技術全景圖

    總結

    以上是生活随笔為你收集整理的采用CreateThread()创建多线程程序的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。