執行個體嘛,就不多做太多說明了。這裡不說worker線程的使用,那種掛回調的東西,不說了。而且幾乎不可控的。這裡只說派生CWinThread方式。這裡基於對話方塊工程給出執行個體。
1、派生CWinThread,不要自己寫代碼了,直接,類別檢視--右鍵add class -- mfc class -- base class設定為CWinThread。
2、添加訊息處理,得到的完整的類代碼如下:
#pragma once#define WM_TEST WM_USER + 105// MyThreadclass MyThread : public CWinThread{DECLARE_DYNCREATE(MyThread)protected:MyThread(); // protected constructor used by dynamic creationvirtual ~MyThread();public:virtual BOOL InitInstance();virtual int ExitInstance(); void OnTest(WPARAM wParam, LPARAM lParam);protected:DECLARE_MESSAGE_MAP()};// MyThread.cpp : implementation file//#include "stdafx.h"#include "ThreadDlg.h"#include "MyThread.h"// MyThreadIMPLEMENT_DYNCREATE(MyThread, CWinThread)MyThread::MyThread(){}MyThread::~MyThread(){}BOOL MyThread::InitInstance(){// TODO: perform and per-thread initialization herereturn TRUE;}int MyThread::ExitInstance(){// TODO: perform any per-thread cleanup herereturn CWinThread::ExitInstance();}void MyThread::OnTest(WPARAM wParam,LPARAM lParam){ AfxMessageBox("test");}BEGIN_MESSAGE_MAP(MyThread, CWinThread) ON_THREAD_MESSAGE(WM_TEST, OnTest)END_MESSAGE_MAP()// MyThread message handlers
3、對話方塊類如下,添加了多線程成員指標:
class CThreadDlgDlg : public CDialogEx{private: MyThread *myThr;
4、修改函數CThreadDlgDlg::OnInitDialog():
BOOL CThreadDlgDlg::OnInitDialog(){CDialogEx::OnInitDialog();// 將“關於...”功能表項目添加到系統功能表中。// IDM_ABOUTBOX 必須在系統命令範圍內。ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);CMenu* pSysMenu = GetSystemMenu(FALSE);if (pSysMenu != NULL){BOOL bNameValid;CString strAboutMenu;bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);ASSERT(bNameValid);if (!strAboutMenu.IsEmpty()){pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);}}// 設定此對話方塊的表徵圖。當應用程式主視窗不是對話方塊時,架構將自動// 執行此操作SetIcon(m_hIcon, TRUE);// 設定大表徵圖SetIcon(m_hIcon, FALSE);// 設定小表徵圖// TODO: 在此添加額外的初始化代碼 myThr = (MyThread *)AfxBeginThread(RUNTIME_CLASS(MyThread));return TRUE; // 除非將焦點設定到控制項,否則返回 TRUE}
5、對話方塊添加一個按鈕,實現點擊事件函數:
void CThreadDlgDlg::OnBnClickedButton1(){ // TODO: Add your control notification handler code here myThr->PostThreadMessage(WM_TEST, 0, 0);}
每次點擊按鈕,就會出發多線程的test函數了。
6、要線程退出怎麼辦?對於worker線程,就是一個回調這種,沒有多大問題,要麼用
void CThreadDlgDlg::OnBnClickedButton1(){ // TODO: Add your control notification handler code here myThr->PostThreadMessage(WM_QUIT, 0, 0);}
7、線程間通訊,同步互斥,以worker線程為例子,在dlg類裡面添加一個CSemaphore成員,然後在建構函式裡面初始化為0,先看一下CSemaphore的建構函式:
CSemaphore( LONG lInitialCount = 1, LONG lMaxCount = 1, LPCTSTR pstrName = NULL, LPSECURITY_ATTRIBUTES lpsaAttributes = NULL );
下面列出完整原始碼:
// CDlgOncloseDlg dialogclass CDlgOncloseDlg : public CDialogEx{ // Constructionpublic: CDlgOncloseDlg(CWnd* pParent = NULL);// standard constructor // Dialog Data enum { IDD = IDD_DLGONCLOSE_DIALOG };protected: virtual void DoDataExchange(CDataExchange* pDX);// DDX/DDV support // Implementationprotected: HICON m_hIcon; // Generated message map functions virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP()public: afx_msg void OnBnClickedButtonNewThr();private: CWinThread *WorkThr; CSemaphore mySem;public: afx_msg void OnBnClickedButtonNewThr2();};CDlgOncloseDlg::CDlgOncloseDlg(CWnd* pParent /*=NULL*/) : CDialogEx(CDlgOncloseDlg::IDD, pParent), mySem(0){ m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);}void CDlgOncloseDlg::DoDataExchange(CDataExchange* pDX){ CDialogEx::DoDataExchange(pDX);}BEGIN_MESSAGE_MAP(CDlgOncloseDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON_NEW_THR, &CDlgOncloseDlg::OnBnClickedButtonNewThr) ON_BN_CLICKED(IDC_BUTTON_NEW_THR2, &CDlgOncloseDlg::OnBnClickedButtonNewThr2)END_MESSAGE_MAP()UINT myThread(LPVOID pParam){ CSemaphore *mySem; if(!pParam) { return -1; } else { mySem = (CSemaphore *)pParam; } while(1) { mySem->Lock(); TRACE("myThread\n"); } return 0;}void CDlgOncloseDlg::OnBnClickedButtonNewThr(){ // TODO: Add your control notification handler code here WorkThr = AfxBeginThread(myThread, (LPVOID)&mySem);}void CDlgOncloseDlg::OnBnClickedButtonNewThr2(){ // TODO: Add your control notification handler code here TRACE("OnBnClickedButtonNewThr2\n"); mySem.Unlock();}
當然,Worker線程最大的作用就是,讓它做一些複雜的事情,把主線程釋放出來,這裡做一個worker,然後主線程等worker完成:
UINT ReadFile(LPVOID in){ CSemaphore *inSem = (CSemaphore *)in; if(!in) { return 0; } for(int i = 1000000000; i > 0; i--) ; inSem->Unlock(); return 0;}void CMFCApplication1View::OnFileOpen(){ if(!dlg ) { dlg = new CtestDlg; dlg->Create(this); dlg->ModifyStyleEx(0, WS_EX_TOPMOST); } dlg->ShowWindow(SW_SHOW); AfxBeginThread(ReadFile, &sem); sem.Lock(); dlg->DestroyWindow(); delete dlg; dlg = NULL;}
8、UI線程,建立對話方塊:
添加對話方塊,添加相應的類為ThrTestDlg,新增成員函數CreateDlg()用於非模態對話方塊建立時候使用,這裡列出完整類定義:
class ThrTestDlg : public CDialogEx{ DECLARE_DYNAMIC(ThrTestDlg)public: BOOL CreateDlg() { return CDialogEx::Create(IDD); }public: ThrTestDlg(CWnd* pParent = NULL); // standard constructor virtual ~ThrTestDlg(); // Dialog Data enum { IDD = IDD_DIALOG1 };protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support DECLARE_MESSAGE_MAP()};
然後,修改UI線程類定義,在init和exit函數裡面,實現建立和銷毀對話方塊:
class CMyThread : public CWinThread{DECLARE_DYNCREATE(CMyThread)protected:CMyThread(); // protected constructor used by dynamic creationvirtual ~CMyThread();public:virtual BOOL InitInstance();virtual int ExitInstance(); void end() { this->PostThreadMessage(WM_QUIT, 0, 0); } ThrTestDlg *dlg;protected:DECLARE_MESSAGE_MAP()};// CMyThreadIMPLEMENT_DYNCREATE(CMyThread, CWinThread)CMyThread::CMyThread(){ dlg = new ThrTestDlg();}CMyThread::~CMyThread(){ delete dlg;}BOOL CMyThread::InitInstance(){// TODO: perform and per-thread initialization here dlg->CreateDlg(); dlg->ModifyStyleEx(0, WS_EX_TOPMOST); dlg->ShowWindow(SW_SHOW);return TRUE;}int CMyThread::ExitInstance(){// TODO: perform any per-thread cleanup here dlg->DestroyWindow();return CWinThread::ExitInstance();}BEGIN_MESSAGE_MAP(CMyThread, CWinThread)END_MESSAGE_MAP()
再修改工程的對話方塊,添加兩個按鈕事件,一個做建立新線程,一個退出前者建立的線程。代碼如下:
void CDlgOncloseDlg::OnBnClickedButtonNewThr(){ // TODO: Add your control notification handler code here WorkThr = AfxBeginThread(RUNTIME_CLASS(CMyThread));}void CDlgOncloseDlg::OnBnClickedButtonNewThr2(){ // TODO: Add your control notification handler code here TRACE("OnBnClickedButtonNewThr2\n"); WorkThr->PostThreadMessageW(WM_QUIT, 0, 0); //mySem.Unlock();}