线程控制 - AfxBeginThreadUI线程的封装类
2016-03-20 16:12
357 查看
前言
UI线程的控制(创建, 启,停,挂起,恢复)需要自己来做,才能精细的控制.e.g. 手术中,医生不能离开病人去吃饭.
对UI线程访问封装后,需要新线程时,需要的代码量会降低,维护方便.
相关封装类参考 : 线程控制 - AfxBeginThread工作者线程的封装类
demo
调用方代码
// testcase5Dlg.h : header file // #if !defined(AFX_TESTCASE5DLG_H__3C5CCF87_B459_4CFC_8B95_3D8D58A26780__INCLUDED_) #define AFX_TESTCASE5DLG_H__3C5CCF87_B459_4CFC_8B95_3D8D58A26780__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include "MyUIThread.h" ///////////////////////////////////////////////////////////////////////////// // CTestcase5Dlg dialog class CTestcase5Dlg : public CDialog { // Construction public: CTestcase5Dlg(CWnd* pParent = NULL); // standard constructor // Dialog Data //{{AFX_DATA(CTestcase5Dlg) enum { IDD = IDD_TESTCASE5_DIALOG }; // NOTE: the ClassWizard will add data members here //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CTestcase5Dlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: HICON m_hIcon; // Generated message map functions //{{AFX_MSG(CTestcase5Dlg) virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); afx_msg void OnButton1(); afx_msg void OnButton2(); afx_msg void OnButton3(); afx_msg void OnButton4(); afx_msg void OnButton5(); //}}AFX_MSG DECLARE_MESSAGE_MAP() private: CMyUIThread m_Thread1; ///< UI线程 CMyUIThread::TAG_REGISTERTHREADPROC m_ThreadParam1; }; //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_TESTCASE5DLG_H__3C5CCF87_B459_4CFC_8B95_3D8D58A26780__INCLUDED_)
// testcase5Dlg.cpp : implementation file // #include "stdafx.h" #include "testcase5.h" #include "testcase5Dlg.h" #include "MyUiWinThread.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for App About class CAboutDlg : public CDialog { public: CAboutDlg(); // Dialog Data //{{AFX_DATA(CAboutDlg) enum { IDD = IDD_ABOUTBOX }; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CAboutDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: //{{AFX_MSG(CAboutDlg) //}}AFX_MSG DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAboutDlg) //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) //{{AFX_MSG_MAP(CAboutDlg) // No message handlers //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CTestcase5Dlg dialog CTestcase5Dlg::CTestcase5Dlg(CWnd* pParent /*=NULL*/) : CDialog(CTestcase5Dlg::IDD, pParent) { //{{AFX_DATA_INIT(CTestcase5Dlg) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CTestcase5Dlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CTestcase5Dlg) // NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CTestcase5Dlg, CDialog) //{{AFX_MSG_MAP(CTestcase5Dlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON1, OnButton1) ON_BN_CLICKED(IDC_BUTTON2, OnButton2) ON_BN_CLICKED(IDC_BUTTON3, OnButton3) ON_BN_CLICKED(IDC_BUTTON4, OnButton4) ON_BN_CLICKED(IDC_BUTTON5, OnButton5) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CTestcase5Dlg message handlers BOOL CTestcase5Dlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here return TRUE; // return TRUE unless you set the focus to a control } void CTestcase5Dlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CTestcase5Dlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR CTestcase5Dlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } void CTestcase5Dlg::OnButton1() { /// UI线程建立 m_ThreadParam1.pUserData = &m_ThreadParam1; m_ThreadParam1.pThreadClass = RUNTIME_CLASS(CMyUiWinThread); m_Thread1.RegisterThreadProc(&m_ThreadParam1); } void CTestcase5Dlg::OnButton2() { /// UI线程启动 m_Thread1.Start(); } void CTestcase5Dlg::OnButton3() { /// UI线程暂停 m_Thread1.Pause(); } void CTestcase5Dlg::OnButton4() { /// UI线程恢复 m_Thread1.Continue(); } void CTestcase5Dlg::OnButton5() { /// UI线程停止 m_Thread1.Stop(); }
线程实现类
#if !defined(AFX_MYUIWINTHREAD_H__DE5A00D4_30ED_4BF0_9B1D_19E7CBEF178E__INCLUDED_) #define AFX_MYUIWINTHREAD_H__DE5A00D4_30ED_4BF0_9B1D_19E7CBEF178E__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 // MyUiWinThread.h : header file // ///////////////////////////////////////////////////////////////////////////// // CMyUiWinThread thread class CMyUIThread; class CMyUiWinThread : public CWinThread { DECLARE_DYNCREATE(CMyUiWinThread) protected: CMyUiWinThread(); // protected constructor used by dynamic creation // Attributes public: // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMyUiWinThread) public: virtual BOOL InitInstance(); virtual int ExitInstance(); virtual int Run(); //}}AFX_VIRTUAL // Implementation protected: virtual ~CMyUiWinThread(); // Generated message map functions //{{AFX_MSG(CMyUiWinThread) // NOTE - the ClassWizard will add and remove member functions here. //}}AFX_MSG DECLARE_MESSAGE_MAP() public: void SetOwner(CMyUIThread* pOwner); private: CMyUIThread* m_pOwner; ///< 所有者 }; ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_MYUIWINTHREAD_H__DE5A00D4_30ED_4BF0_9B1D_19E7CBEF178E__INCLUDED_)
// MyUiWinThread.cpp : implementation file // #include "stdafx.h" #include "testcase5.h" #include "MyUiWinThread.h" #include "MyUIThread.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CMyUiWinThread IMPLEMENT_DYNCREATE(CMyUiWinThread, CWinThread) CMyUiWinThread::CMyUiWinThread() { } CMyUiWinThread::~CMyUiWinThread() { } BOOL CMyUiWinThread::InitInstance() { // TODO: perform and per-thread initialization here return TRUE; } int CMyUiWinThread::ExitInstance() { // TODO: perform any per-thread cleanup here return CWinThread::ExitInstance(); } BEGIN_MESSAGE_MAP(CMyUiWinThread, CWinThread) //{{AFX_MSG_MAP(CMyUiWinThread) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMyUiWinThread message handlers void CMyUiWinThread::SetOwner(CMyUIThread* pOwner) { m_pOwner = pOwner; } int CMyUiWinThread::Run() { BOOL bFirst = TRUE; CWnd* pWnd = NULL; if (NULL != m_pOwner) { do { Sleep(1); if (m_pOwner->cbIsNeedQuit()) { TRACE(_T("NeedQuit\n")); break; ///< 如果线程函数退出判断点有多个, 此代码块按需调用 } if (!m_pOwner->cbIsCanContinue()) { continue; ///< 如果线程函数继续判断点有多个, 此代码块按需调用 } if (bFirst) { bFirst = FALSE; TRACE(_T("CMyUiWinThread::ThreadProc running\n")); } } while (1); TRACE(_T("<< CMyUiWinThread::ThreadProc\n")); } /// 不会经过 CMyUiWinThread::ExitInstance(), 自己要调用一下 this->ExitInstance(); ///< ! return S_OK; ///< 线程退出码 // return CWinThread::Run(); ///< ! don't call, 否则在GetMessage那等消息阻塞住了 }
线程访问控制类
// MyUIThread.h: interface for the CMyUIThread class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_MYUITHREAD_H__8B713CD4_E5C4_467D_87C0_B5197689E5C8__INCLUDED_) #define AFX_MYUITHREAD_H__8B713CD4_E5C4_467D_87C0_B5197689E5C8__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 class CMyUIThread { public: typedef BOOL (CMyUIThread::*PFN_IS)(); typedef struct _tag_RegisterThreadproc { IN void* pUserData; ///< 用户数据指针, 我们不动, 线程自己用 IN CRuntimeClass* pThreadClass; ///< 传入的线程处理对象 /// 线程控制类指针, 配合下面2个回调函数使用 OUT CMyUIThread* pThreadControlClass; /// 传出的回调函数指针, 提供给线程函数用来判断是继续还是挂起 OUT PFN_IS pfnIsCanContinue; /// 传出的回调函数指针, 提供给线程函数判断是否要退出线程 OUT PFN_IS pfnIsNeedQuit; _tag_RegisterThreadproc() { pUserData = NULL; pThreadClass = NULL; pThreadControlClass = NULL; pfnIsCanContinue = NULL; pfnIsNeedQuit = NULL; } } TAG_REGISTERTHREADPROC; public: CMyUIThread(); virtual ~CMyUIThread(); void RegisterThreadProc(CMyUIThread::TAG_REGISTERTHREADPROC* pParam); ///< 注册回调函数 void Start(); ///< 线程开始 void Pause(); ///< 线程挂起 void Continue(); ///< 线程恢复运行 void Stop(); ///< 线程停止 BOOL cbIsCanContinue(); ///< 给线程函数的回调-是否可以继续运行线程 BOOL cbIsNeedQuit(); ///< 给线程函数的回调-是否退出线程 private: CWinThread* m_pWinThread; ///< 线程对象指针 CRuntimeClass* m_pThreadClass; ///< 线程处理对象 UINT m_uThreadId; ///< 线程ID HANDLE m_hEventContinue; ///< 事件句柄 - 继续 HANDLE m_hEventQuit; ///< 事件句柄 - 退出线程 void* m_pUserData; ///< 用户数据指针, 我们不动, 创建线程时, 当线程参数 }; #endif // !defined(AFX_MYUITHREAD_H__8B713CD4_E5C4_467D_87C0_B5197689E5C8__INCLUDED_)
// MyUIThread.cpp: implementation of the CMyUIThread class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include <process.h> #include "MyUIThread.h" #include "MyUiWinThread.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CMyUIThread::CMyUIThread() { m_pWinThread = NULL; m_pThreadClass = NULL; m_uThreadId = (UINT)-1; m_pUserData = NULL; /// 事件对象用于通知机制时的创建要求, 手工复位, 有信号 m_hEventContinue = CreateEvent(NULL, TRUE, TRUE, NULL); m_hEventQuit = CreateEvent(NULL, TRUE, TRUE, NULL); } CMyUIThread::~CMyUIThread() { Stop(); } void CMyUIThread::RegisterThreadProc(CMyUIThread::TAG_REGISTERTHREADPROC* pParam) { if ((NULL != pParam) && (NULL != pParam->pThreadClass)) { if (m_pThreadClass != pParam->pThreadClass) { Stop(); /// 线程入参 m_pThreadClass = pParam->pThreadClass; m_pUserData = pParam->pUserData; /// 填充出参 pParam->pThreadControlClass = this; pParam->pfnIsCanContinue = cbIsCanContinue; pParam->pfnIsNeedQuit = cbIsNeedQuit; } } } void CMyUIThread::Start() { if (NULL != m_pThreadClass) { TRACE(_T("CMyUIThread::Start()\n")); Stop(); Continue(); m_pWinThread = AfxBeginThread( m_pThreadClass, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL); if (m_pWinThread->IsKindOf(RUNTIME_CLASS(CMyUiWinThread))) { ((CMyUiWinThread*)m_pWinThread)->SetOwner(this); } m_pWinThread->m_bAutoDelete = FALSE; m_pWinThread->ResumeThread(); } } void CMyUIThread::Pause() { TRACE(_T("CMyUIThread::Pause\n")); ResetEvent(m_hEventContinue); } void CMyUIThread::Continue() { TRACE(_T("CMyUIThread::Continue\n")); SetEvent(m_hEventContinue); } BOOL CMyUIThread::cbIsCanContinue() { TRACE(_T("CMyUIThread::cbIsCanContinue\n")); WaitForSingleObject(m_hEventContinue, INFINITE); return TRUE; } BOOL CMyUIThread::cbIsNeedQuit() { DWORD dwRc = WaitForSingleObject(m_hEventQuit, 0); TRACE(_T("CMyUIThread::cbIsNeedQuit\n")); return (WAIT_OBJECT_0 == dwRc); } void CMyUIThread::Stop() { TRACE(_T("CMyUIThread::Stop\n")); SetEvent(m_hEventQuit); Continue(); if (NULL != m_pWinThread) { WaitForSingleObject(m_pWinThread->m_hThread, INFINITE); delete m_pWinThread; m_pWinThread = NULL; } ResetEvent(m_hEventQuit); }
相关文章推荐
- UITableView增加搜素框后搜不出来内容(old)
- DirectUI开源项目网站
- String、StringBuffer、StringBuilder
- JavaGUI发展状况(持续更新)
- OwinBuilder源码阅读
- 哈希表key_value形式
- <jsp:setProperty property="*" name="stuInfo" />的用法
- Java基础之十六:GUI基础
- [LeetCode] Shortest Distance from All Buildings 建筑物的最短距离
- Win7 64位 VS2015环境编译cegui-0.8.5
- SOAPUI 接口自动化学习笔记节选 如何用Groovy 脚本读取CSV 文件
- UESTC1012(水)
- SDUT Fruit Ninja II (2416 积分)
- spark 1.6 下parquet vs orc
- 利用PBFunc在Powerbuilder中解析Json对象
- 关于fineui中在gird中插入按钮的知识
- UESTC 1034 AC Milan VS Juventus 分情况讨论
- CROC 2016 - Qualification B. Processing Queries 模拟
- EasyUi textbox 事件 numberspinner事件
- 《iOS Human Interface Guidelines》——Web View