採用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?- //執行緒函式宣告
- DWORD WINAPI ThreadProc(LPVOIDlpParam);
- //為了傳遞多個引數,我採用結構體
- struct threadInfo
- {
- HWND hWnd; //視窗控制代碼
- int nOffset; //偏移量
- COLORREF clrRGB; //顏色
- };
- protected:
- HANDLE hThead[3]; //用於儲存執行緒控制代碼
- DWORD dwThreadID[3];//用於儲存執行緒的ID
- threadInfo Info[3]; //傳遞給執行緒處理函式的引數
//實現檔案中
[cpp] view plain copy 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);
- //建立執行緒
- 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;
- }
執行效果:
單執行緒測試
多執行緒測試
工程原始碼下載地址:
歡迎大家修改和指正。
注意事項:
(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