1. 程式人生 > >採用CreateThread()建立多執行緒程式 MFC

採用CreateThread()建立多執行緒程式 MFC

採用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 avoid 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 plain copy print?
  1. //執行緒函式宣告
  2. DWORD WINAPI ThreadProc(LPVOIDlpParam);  
  3. //為了傳遞多個引數,我採用結構體
  4. struct threadInfo  
  5. {  
  6.     HWND hWnd;       //視窗控制代碼
  7.     int  nOffset;    //偏移量
  8.     COLORREF clrRGB; //顏色
  9. };  
  10. protected:  
  11. HANDLE hThead[3];    //用於儲存執行緒控制代碼
  12.     DWORD  dwThreadID[3];//用於儲存執行緒的ID
  13.   threadInfo Info[3];   //傳遞給執行緒處理函式的引數


//實現檔案中

[cpp] view plain copy print?
  1. //單執行緒測試
  2. void CMultiThread_1Dlg::OnBnClickedButton1()  
  3. {  
  4.     // TODO: 在此新增控制元件通知處理程式程式碼
  5.     //使能按鈕
  6.     GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);  
  7.     GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);  
  8.     CDC *dc = GetDC();  
  9.     CRect rt;  
  10.     GetClientRect(rt);  
  11.     dc->FillSolidRect(0,0,rt.Width(),rt.Height()-70,RGB(240,240,240));//重新整理背景
  12.     dc->TextOut(97,470,"#1");  
  13.     dc->TextOut(297,470,"#2");  
  14.     dc->TextOut(497,470,"#3");  
  15.     //#1
  16.     for (int i=0;i<460;i++)  
  17.     {  
  18.        for (int j =10 ;j<200;j++)  
  19.        {  
  20.            dc->SetPixel(j,460-i,RGB(255,0,0));  
  21.        }  
  22.     }  
  23.     //#2
  24.     for (int i=0;i<460;i++)  
  25.     {  
  26.        for (int j =210 ;j<400;j++)  
  27.         {  
  28.            dc->SetPixel(j,460-i,RGB(0,255,0));  
  29.        }  
  30.     }  
  31.     //#3
  32.     for (int i=0;i<460;i++)  
  33.     {  
  34.        for (int j =410 ;j<600;j++)  
  35.        {  
  36.            dc->SetPixel(j,460-i,RGB(0,0,255));  
  37.        }  
  38.     }  
  39.     ReleaseDC(dc);  
  40.     //使能按鈕
  41.     GetDlgItem(IDC_BUTTON1)->EnableWindow(TRUE);  
  42.     GetDlgItem(IDC_BUTTON2)->EnableWindow(TRUE);  
  43. }  
  44. //多執行緒測試
  45. void CMultiThread_1Dlg::OnBnClickedButton2()  
  46. {  
  47.     // TODO: 在此新增控制元件通知處理程式程式碼
  48.     CDC *dc = GetDC();  
  49.     CRect rt;  
  50.     GetClientRect(rt);  
  51.     dc->FillSolidRect(0,0,rt.Width(),rt.Height()-70,RGB(240,240,240));//重新整理背景
  52.     dc->TextOut(97,470,"#1");  
  53.     dc->TextOut(297,470,"#2");  
  54.     dc->TextOut(497,470,"#3");  
  55.     //初始化執行緒的引數
  56.     Info[0].hWnd = Info[1].hWnd = Info[2].hWnd = GetSafeHwnd();  
  57.     Info[0].nOffset = 10;Info[1].nOffset = 210;Info[2].nOffset = 410;  
  58.     Info[0].clrRGB = RGB(255,0,0);Info[1].clrRGB= RGB(0,255,0);Info[2].clrRGB = RGB(0,0,255);  
  59.     //建立執行緒
  60.     for (int i = 0;i<3;i++)  
  61.     {  
  62.        hThead[i] = CreateThread(NULL,0,ThreadProc,&Info[i],0,&dwThreadID[i]);  
  63.     }  
  64.     ReleaseDC(dc);  
  65. }  
  66. DWORD WINAPI ThreadProc(LPVOIDlpParam)  
  67. {  
  68.     threadInfo*Info = (threadInfo*)lpParam;  
  69.     CDC *dc = CWnd::FromHandle(Info->hWnd)->GetDC();  
  70.     for (int i=0;i<460;i++)  
  71.     {  
  72.        for (int j=Info->nOffset;j<Info->nOffset+190;j++)  
  73.        {  
  74.            dc->SetPixel(j,460-i,Info->clrRGB);  
  75.        }  
  76.     }  
  77.     DeleteObject(dc);  
  78.     return 0;  
  79. }  


執行效果:

單執行緒測試


多執行緒測試

工程原始碼下載地址:

歡迎大家修改和指正。

注意事項:

(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指標,以便直接呼叫。

structthreadInfo

{

    CDC * dc;        //畫布

    int nOffset;    //偏移量

    COLORREFclrRGB; //顏色

};

//多執行緒測試

voidCMultiThread_1Dlg::OnBnClickedButton2()

{

    // TODO:在此新增控制元件通知處理程式程式碼

    CDC *dc =GetDC();

    CRectrt;

    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 (inti = 0;i<3;i++)

    {

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

    }

    //ReleaseDC(dc);

}

//執行緒執行函式

DWORDWINAPI ThreadProc(LPVOIDlpParam)

{

    threadInfo*Info = (threadInfo*)lpParam;

    for (inti=0;i<460;i++)

    {

       for (intj=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 : 標頭檔案

//宣告執行緒處理函式

DWORDWINAPI ThreadProc1(LPVOIDlpParam);

DWORDWINAPI ThreadProc2(LPVOIDlpParam);

//為了傳遞多個引數,我採用結構體

structthreadInfo1

{

    HWNDhWnd;       //視窗控制代碼

    int nOffset;    //偏移量

};

structthreadInfo2

{

    HWNDhWnd;          //視窗控制代碼

    HANDLE *phHandle;   //偏移量

};

protected:

    long  m_nTime;//時間

    HANDLEm_hThead[5];    //用於儲存執行緒控制代碼

    HANDLEhThead;     //用於儲存執行緒控制代碼

    DWORD m_dwThreadID[5];//用於儲存執行緒的ID

    threadInfo1Info1[5];  //傳遞給執行緒處理函式的引數

    threadInfo2Info2;

// MulitThread_2Dlg.cpp : 實現檔案

//更新時間:毫秒

voidCMulitThread_2Dlg::OnTimer(UINT_PTRnIDEvent)

{

    // TODO:在此新增訊息處理程式程式碼和/或呼叫預設值

    m_nTime+=100;//毫秒為單位

    CStringstr;

    str.Format("時間:%.1f秒",m_nTime/1000.0);

    GetDlgItem(IDC_STATIC2)->SetWindowText(str);

    CDialog::OnTimer(nIDEvent);

}

//訊息處理函式

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

}

//開始比賽

voidCMulitThread_2Dlg::OnBnClickedButton1()

{

    // TODO:在此新增控制元件通知處理程式程式碼

    //使能開始按鈕:無效

    GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);

    m_nTime =0;//初始化時間為

    CDC *dc =GetDC();

    CRectrt;

    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 (inti = 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 (inti = 0;i<5;i++)

    {  

       ResumeThread(m_hThead[i]); 

    }

    //開始執行監測結果執行緒

    Info2.hWnd =m_hWnd;

    Info2.phHandle =m_hThead;

    hThead =CreateThread(NULL,0,ThreadProc2,&Info2,0,NULL);

}

//比賽執行緒

DWORDWINAPI ThreadProc1(LPVOIDlpParam)

{

    threadInfo1*info = (threadInfo1*)lpParam;

    CDC *dc =CWnd::FromHandle(info->hWnd)->GetDC();

    for (inti=40;i<570;i+=2)

    {

       for (intj=0;j<1000;j++)

       {//重複操作,以便人眼觀察

           dc->Rectangle(CRect(i,info->nOffset,i+1,info->nOffset+80));

       }

    }

    DeleteObject(dc);

    return 0;

}

//監視執行緒:誰先完成比賽就結束

DWORDWINAPI ThreadProc2(LPVOIDlpParam)

{

    threadInfo2*info = (threadInfo2*)lpParam;

    DWORDdwRet = 0;

    //等待個執行緒中的一個完成

    dwRet =WaitForMultipleObjects(5,info->phHandle,FALSE,INFINITE);

    if (dwRet ==WAIT_FAILED)

    {//出錯啦

       ::SendMessage(info->hWnd,WM_GAMEOVER,0,0);

       return 0;

    }

    //終止各個執行緒

    for (inti=0;i<5;i++)

    {

       TerminateThread(info->phHandle[i],0);

    }

    //傳送比賽結果訊息

    ::SendMessage(info->hWnd,WM_GAMEOVER,1,dwRet-WAIT_OBJECT_0);

    return 0;

}

執行結果:

工程原始碼下載地址:

歡迎大家修改和指正。

注意事項:

1.    該程式連主執行緒一共7個執行緒。其中一個執行緒專門用於檢測5個比賽執行緒的執行結果檢測,為什麼要專門開這個執行緒而不在主執行緒中進行呢?主要是WaitForMultipleObjects()函式是一個阻塞函式,如果在主執行緒中執行該函式,將使整個程式的介面不能操作(如:不能移動視窗等),因為一直阻塞在WaitForMultipleObjects函式處,而不能處理其它訊息,不信大家可以試試。

2.    執行緒同步的兩個比較重要的函式為WaitForSingleObject()和WaitForMultipleObjects(),具體使用請參考MSDN。這兩個函式都是阻塞函式,一直等待授信的物件發生才返回。

3.    採用訊息的方式通知主執行緒的執行結果,該方法比較簡單有效。一般的多執行緒程式都是採用主執行緒負責顯示,輔助執行緒來完成比較耗時的任務,等任務完成後再通知主執行緒執行結果。

轉載請說明出處,謝謝。

相關推薦

採用CreateThread()建立執行程式 MFC

採用CreateThread()建立多執行緒程式 在window環境下,Win32 提供了一系列的API函式來完成執行緒的建立、掛起、恢復、終結以及通訊等工作: 1、主要的函式列表: 序號 函式名 功能 1 CreateThread() 建立一個新執行

作業系統,核心定時器:使用“訊號”建立一種使用者空間機制來測量一個執行程式執行時間。

      核心是一個作業系統的核心。它負責管理系統的程序、記憶體、裝置驅動程式、檔案和網路系統,決定著系統的效能和穩定性。 定時器是Linux提供的一種定時服務的機制,它在某個特定的時間喚醒某個程序來進行工作。核心在時鐘中斷髮生後檢測各定時器是否到期,在li

MFC建立執行

FC中有兩類執行緒,分別稱之為工作執行緒和使用者介面執行緒。工作執行緒沒有訊息機制,通常用來執行後臺計算和維護任務,如冗長的計算過程,印表機的後臺列印等;使用者介面執行緒有自己的訊息機制,一般用於處理獨立於其他執行緒執行之外的使用者輸入,響應使用者及系統所產生的事件和訊息等。本文主要講述如何在MFC

Java 建立執行

1、繼承java.lang.Thread方式 執行start方法:MyThread的run就會被執行 程式碼片段: import java.util.Scanner; public class Main { public static void main(String[] a

linux下C開發執行程式

轉:https://blog.csdn.net/lingfemg721/article/details/6574804   linux下用C開發多執行緒程式,Linux系統下的多執行緒遵循POSIX執行緒介面,稱為pthread。   #

beginthreadex()函式在建立執行傳入回撥函式時,好像只能傳入全域性函式或類的靜態成員函式,請問能不能傳入類的成員函式呢(非靜態)?

C++類成員函式直接作為執行緒回撥函式2009年06月01日 星期一 17:01我以前寫執行緒時要麼老老實實照著宣告寫,要麼使用C++類的靜態成員函式來作為回撥函式,經常會因為執行緒程式碼而破壞封裝.之前雖然知道類成員函式的展開形式,但從沒想過利用過它,昨天看深入ATL時無意中學

Python建立執行任務並獲取每個執行返回值

轉自:https://www.cnblogs.com/bethansy/p/7965820.html 1.程序和執行緒     (1)程序是一個執行中的程式。每個程序都擁有自己的地址空間、記憶體、資料棧以及其他用於跟蹤執行的輔助資料。程序也可以派生新的程序來執行其他任務,

建立執行的4種方式

1.執行緒是什麼?         執行緒被稱為輕量級程序,是程式執行的最小單位,它是指在程式執行過程中,能夠執行程式碼的一個執行單位。每個程式程式都至少有一個執行緒,也即是程式本身。 2.執行緒狀態         Jav

python執行———2、建立執行的兩種方式

 法一、使用Thread類例項化 法二、繼承Thread來實現多執行緒 #對於io操作來說,多執行緒和多程序效能差別不大 #1、使用Thread類例項化 import time import threading def get_detail_html(url): prin

如何建立執行

方式1:繼承Thread類 步驟: 1):定義一個類A繼承於Java.lang.Thread類. 2):在A類中覆蓋Thread類中的run方法. 3):我們在run方法中編寫需要執行的操作:run方法裡的程式碼,執行緒執行體. 4):在main方法(執行緒)中,建立執行緒物件,並啟動執行緒. (

建立執行的兩種方法

建立執行緒的方法: 一種方法是將類宣告為 Thread 的子類。該子類應重寫 Thread 類的 run 方法。接下來可以分配並啟動該子類的例項。 public class MyThread extends Thread{

java:執行程式的實現方式

1.一種方法是將類宣告為 Thread 的子類。該子類應重寫 Thread 類的 run 方法。 public class Demo2_Thread { public static void main(String[] args) { MyThread mt=new MyThread

JAVA執行程式造成系統時鐘變快

新增jvm引數 註冊為系統服務修改: D:\Tomcat7.0\bin\tomcat7w.exe  在Java面Java Options下最後新增:  -XX:+ForceTimeHighResolution  ---------------------

建立執行的三種方式

執行緒是指程序內部同時做的事情,比如在玩王者榮耀的時候,你可以同時攻擊英雄A和英雄B; 下面將此作為例子,引入三種建立多執行緒的方式; 例子思路:                  ①先建立英雄類(Hero)設定三個屬性:name(英雄名)、hp(英雄的血量)、dama

beginThreadex建立執行解讀

_beginThreadex建立多執行緒解讀 一、需要的標頭檔案支援  #include <process.h>         // for _beginthread() 需要的

QtConcurrent系列之run函式建立執行

        在Qt多執行緒程式設計中,我們一般使用QThread,QRunnable等類來實現多執行緒。除此之外,QT還提供了一個更高階的實現多執行緒的方式,那就是QtConcurrent框架,QtConcurrent框架中提供了許多高階的,效能更好的多執行緒API函式,

對於執行程式,單核cpu與核cpu是怎麼工作的

此文中的大部分資料來自於網路上,我只是覺得把有道理的整理一下,方便以後查閱。 1.多執行緒在單核和多核CPU上的執行效率問題的討論a1: 多執行緒在單cpu中其實也是順序執行的,不過系統可以幫你切換那個執行而已,其實並沒有快(反而慢)多個cpu的話就可以在兩個cpu中同時執行了.....

java建立執行&建立程序

概述 併發和並行是即相似又有區別: 並行:指兩個或多個事件在同一時刻發生; 併發:指兩個或多個事件在同一時間段內發生。 程序是指一個記憶體中執行中的應用程式。每個程序都有自己獨立的一塊記憶體空間,一個應用程式可以同時啟動多個程序。比如在Windows系統中,一個執行的abc.exe就是一個程序。 那麼我們

python_day29_通過類建立執行_佇列

#Author:'haijing'#date:2018/12/20import threadingimport time#通過類建立多執行緒class MyThread(threading.Thread): #MyThread類繼承threading.Thread類 def __init__(self

第一個執行程式

#include<windows.h> #include <iostream> DWORD WINAPI fun1Proc( LPVOID lpParameter //thread data ); DWORD WINAPI fun2