在MFC里面實現線程的實例


線程是一種從軟件到硬件的技術,主要目的是為了提高運行速度,和多任務。

××××××××××××××××××××××××××××××××××××需要儲備的資料(他人的)×××××××××××××××××××××××××××× 

××http://haobinnan.blog.51cto.com/775253/658446

多線程概述

 

 

         進程和線程都是操作系統的概念。進程是在基於內存的概念,線程是基於CPU的概念。CPU不清楚什么玩意叫進程,CPU處理的任務叫線程。一個進程可以划分成多個線程給CPU處理。一個程序可以有多個進程 用於處理不同的事情。


          進程是應用程序的執行實例,每個進程是由私有的虛擬地址空間、代碼、數據和其它各種系統資源組成,進程在運行過程中創建的資源隨着進程的終止而被銷毀,所使用的系統資源在進程終止時被釋放或關閉。


         線程是進程內部的一個執行單元,系統創建好進程后,實際上就啟動執行了該進程的主執行線程,主執行線程以函數地址形式,比如說main或WinMain函數,將程序的啟動點提供給Windows系統。主執行線程終止了,進程也就隨之終止。


         每一個進程至少有一個主執行線程,它無需由用戶去主動創建,是由系統自動創建的。用戶根據需要在應用程序中創建其它線程,多個線程並發地運行於同一個進程中。一個進程中的所有線程都在該進程的虛擬地址空間中,共同使用這些虛擬地址空間、全局變量和系統資源,所以線程間的通訊非常方便,多線程技術的應用也較為廣泛。


         MFC中有兩類線程,分別稱之為工作者線程和用戶界面線程。二者的主要區別在於工作者線程沒有消息循環,而用戶界面線程有自己的消息隊列和消息循環。

         在MFC中,一般用全局函數AfxBeginThread()來創建並初始化一個線程的運行,該函數有兩種重載形式,(為啥叫重載形式呢?因為系統中已經有了這兩個函數,在使用的使用給予不同的變量不就是重載的定義嗎??是的)分別用於創建工作者線程和用戶界面線程。兩種重載函數原型和參數分別說明如下: 

CreateThread是一個API,而AfxBeginThread是MFC中的一個函數。后者在內部調用了前者。

×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

      對於工作線程來說,啟動一個線程,首先需要編寫一個希望與應用程序的其余部分並行運行的函數如Fun1(),

接着定義一個指向CwinThread對象的指針變量*pThread,(在MFC中可以用App)

調用AfxBeginThread(Fun1,param,priority)函數,返回值付給pThread變量的同時一並啟動該線程來執行上面的Fun1()函數,

其中Fun1是線程要運行的函數的名字,也既是上面所說的控制函數的名字,param是准備傳送給線程函數 Fun1的任意32位值,

priority則是定義該線程的優先級別,它是預定義的常數。

線程函數是回調函數,線程函數在類內必須是靜態成員函數,或者是類外聲明的全局函數。

因為靜態成員函數不能訪問類的非靜態成員函數,所以在線程函數中要定義一個類的指針指向this指針,就可以用類的指針來調用類的成員函數。

數據傳遞使用this處理。

 

HMI  WORK線程   

CWinThread* AfxBeginThread(

                       AFX_THREADPROC pfnThreadProc,//指向工作者線程的執行函數的指針,線程函數原型必須聲明如下: UINTExecutingFunction(LPVOID pParam);

                        LPVOID pParam,/**///傳遞給線程函數的一個32位參數,執行函數將用某種方式解釋該值。它可以是數值,或是指向一個結構的指針,甚至可以被忽略;

                      nPriority=THREAD_PRIORITY_NORMAL,//線程的優先級。如果為0,則線程與其父線程具有相同的優先級;

                       UINTnStackSize=0,//線程為自己分配堆棧的大小,其單位為字節。如果nStackSize被設為0,則線程的堆棧被設置成與父線程堆棧相同大小;

                       DWORDdwCreateFlags=0,//如果為0,則線程在創建后立刻開始執行。如果為CREATE_SUSPEND,則線程在創建后立刻被掛起;

                      LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL//線程的安全屬性指針,一般為NULL

);

 


一個工作線程創建的實例: 環境是VS2010  MFC  Win7  64位系統。

 

<span style="background-color: rgb(0, 204, 204);">public:
	//工作線程創建第一步:在某個頭文件里面聲明一個函數。
	static UINT Scada_Operational(LPVOID pParam);
	int aaa;
};

extern CTestApp theApp;
</span>

×××

 

 

<span style="background-color: rgb(0, 204, 204);">//工作線程創建第二步:在對應的實現文件里面,定義這個函數。
UINT CTestApp::Scada_Operational(LPVOID pParam)
{
	Sleep(1000);
	AfxMessageBox(_T("准備賦值"));
	CTestApp* theApp = (CTestApp*)pParam;
	int bb=0;

	bb= theApp->aaa;
	Sleep(1000);
	AfxMessageBox(_T("完成賦值"));

	return 0;
}</span>


×××

 

 

<span style="background-color: rgb(0, 204, 204);">//工作線程創建第三步:使用MFC特有的函數AfxBeginThread 將函數變為線程。
	AfxBeginThread(Scada_Operational,this);</span>

源代碼:http://pan.baidu.com/s/1mgrAxVM
×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

 



  UI線程

創建一個用戶界面線程,首先要從類CwinThread產生一個派生類,同時必須使用DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE來聲明和實現這個CwinThread派生類。
  第二步是根據需要重載該派生類的一些成員函數如:ExitInstance();InitInstance();OnIdle(); PreTranslateMessage()等函數,最后啟動該用戶界面線程,調用AfxBeginThread()函數的一個版   本:

CWinThread*AfxBeginThread(

 

CRuntimeClass* pThreadClass,//從CWinThread派生的RUNTIME_CLASS類;

                       intnPriority=THREAD_PRIORITY_NORMAL,//線程優先級,如果為0,則與創建該線程的線程相同;

                       UINT nStackSize=0,//線程的堆棧大小,如果為0,則與創建該線程的線程相同;

                       DWORD dwCreateFlags=0,//一個創建標識,如果是CREATE_SUSPENDED,

則在懸掛狀態創建線程,在線程創建后線程掛起,否則線程在創建后開始線程的執行。

                       LPSECURITY_ATTRIBUTESlpSecurityAttrs=NULL//線程的安全屬性,NT下有用。

);

 范例 :

 

1、建立一個基於MFC的對話框應用程序。
2、向程序中添加一個以CWinThread為基類的新類CUIThread,該類用於啟動一個用戶界面線程。
3、向程序中添加一個對話框資源,並建立相應的對話框類CUIThreadDlg,這個對話框的基類是CDialogEx。

    該對話框將被作為用戶界面線程的主窗口。
4、在UIThread.h中加入#include "UIThreadDlg.h"和 

public:
	CUIThreadDlg m_dlg;

並在CUIThread::InitInstance()中加入

BOOL CUIThread::InitInstance()
{
	// TODO: 在此執行任意逐線程初始化

	 
	//用戶線程第六步:添加創建程序
	m_pMainWnd = &m_dlg;
	m_dlg.DoModal();
 ;
	return TRUE;
}



5、CUIThread::InitInstance()中創建的CUIThreadDlg將與主窗口在獨立的線程中運行,可以在CUIThreadDlg中加入各種執行耗時任務的代碼而不會影響主窗口的運行。
6、在 原始對話框上面添加一個按鈕 並創建點擊事件響應函數,

//用戶線程第七步:添加線程的頭文件#include "UIThread.h"。

在函數中添加線程創建

void CTestGszDlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知處理程序代碼
	//CWinThread* p = AfxBeginThread(RUNTIME_CLASS(CUIThread));
	//用戶線程第八步:正式創建線程
	 AfxBeginThread(RUNTIME_CLASS(CUIThread));
}
 

7:我們創建的線程在結束的時候 銷毀我們新建的對話框

int CUIThread::ExitInstance()
{
    m_dlg.DestroyWindow();
    return CWinThread::ExitInstance();
}

配套源代碼:http://pan.baidu.com/s/1jGzLTye

××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

幾個常用的配套函數

 

 

//獲取線程對象

CWinThreadAFXAPIAfxGetThread();

//獲取當前消息

MSGAFXAPIAfxGetCurrentMessage();

//結束線程執行

void AFXAPIAfxEndThread(UINTnExitCode,BOOLbDelete =TRUE);

//初始化線程

void AFXAPIAfxInitThread();

//終止線程執行

void AFXAPIAfxTermThread(HINSTANCEhInstTerm =NULL);


 


 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM