您的位置:首页 > 产品设计 > UI/UE

线程控制 - 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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: