首页 > 技术文章 > C++/MFC中多线程使用

sclu 2019-10-08 18:52 原文

一。创建线程的三种方式

1.CreateThread (windows中vc++)

CreateThread(
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, //线程属性
    _In_ SIZE_T dwStackSize, //栈空间大小
    _In_ LPTHREAD_START_ROUTINE lpStartAddress, //线程执行函数地址
    _In_opt_ __drv_aliasesMem LPVOID lpParameter, //传递参数
    _In_ DWORD dwCreationFlags, //标志,可以选择挂起
    _Out_opt_ LPDWORD lpThreadId //线程id
    );
 1 DWORD WINAPI ThreadProc(LPVOID lpParameter)
 2 {
 3     int a = (int)lpParameter;
 4     CString str;
 5     str.Format(_T("%d"),a);
 6     AfxMessageBox(str);
 7     return 0;
 8 }
 9 void CSegDlg::OnBnClickedstop()
10 {
11     // TODO: 在此添加控件通知处理程序代码
12     DWORD dwThreadId = 0; //线程id
13     HANDLE hThread=CreateThread(NULL, 0, ThreadProc, (LPVOID)123, 0, &dwThreadId); //返回线程句柄
14     //关闭句柄,线程结束后释放
15     CloseHandle(hThread);
16 }

2.AfxBeginThread(MFC)

CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam,
	int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0,
	DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);  //创建工作线程,工作线程用来处理一些逻辑
CWinThread* AFXAPI AfxBeginThread(CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL); //创建界面线程,界面线程会有消息循环
 1 UINT _cdecl ThreadProc(LPVOID lpParameter)
 2 {
 3     int a = (int)lpParameter;
 4     CString str;
 5     str.Format(_T("%d"), a);
 6     AfxMessageBox(str);
 7     return 0;
 8 }
 9 void CSegDlg::OnBnClickedstop()
10 {
11     // TODO: 在此添加控件通知处理程序代码
12     CWinThread *pThread=AfxBeginThread(ThreadProc, (LPVOID)456);
13 
14 }

 3._beginthread

 

二。子线程使用主线程参数

1.子线程对应于一个普通函数,不能被简单的声明成主对话框类的成员函数,因此不能使用主对话框(主线程)的参数,需要在创建线程时,将主对话框类对象的指针传递给子线程。子线程通过指针去访问主线程的变量。

 1 UINT _cdecl ThreadProc(LPVOID lpParameter)
 2 {
 3     CSegDlg* pSegDlg = (CSegDlg *)lpParameter; //转换为主对话框类的指针
 4     int a = pSegDlg->num;
 5     CString str;
 6     str.Format(_T("%d"), a);
 7     AfxMessageBox(str);
 8     return 0;
 9 }
10 void CSegDlg::OnBnClickedstop()
11 {
12     num = 100; //成员变量
13     CWinThread *pThread=AfxBeginThread(ThreadProc, this);
14 }

 2.如果一定要将子线程函数声明为类成员函数,需要定义为静态成员函数

 1 UINT _cdecl CSegDlg::ThreadProc(LPVOID lpParameter) //static函数
 2 {
 3     CSegDlg* pSegDlg = (CSegDlg *)lpParameter; //仍然需要传递对象指针,因为static关键词没有this指针
 4     int a = pSegDlg->num;  
 5     CString str;
 6     str.Format(_T("%d"), a);
 7     AfxMessageBox(str);
 8     return 0;
 9 }
10 void CSegDlg::OnBnClickedstop()
11 {
12     num = 100;
13     CWinThread *pThread=AfxBeginThread(ThreadProc, this);
14 }

 

三。创建界面线程。

1.如同主对话框创建时一样,会有一个应用程序类App,如果需要再创建一个线程来管理对话框,需要创建自定义类,继承于CWinThread类。

2.创建好的App类和对话框类如下图所示。

 

 需要在CUIThreadApp中添加CTestDlg.h

3.重写CUIThreadApp中的InitInstance()和ExitInstance()函数。进行对话框的创建和资源的释放。

 1 BOOL CUIThreadApp::InitInstance()
 2 {
 3     // TODO:    在此执行任意逐线程初始化
 4     /*CTestDlg dlg;  //创建模态对话框
 5     dlg.DoModal(); //阻塞
 6     return FALSE; //return FALSE会释放线程
 7     */
 8 
 9 
10     CTestDlg* dlg = new CTestDlg();
11     dlg->Create(IDD_DIALOG1);
12     dlg->ShowWindow(SW_SHOW);
13     dlg->RunModalLoop();  // 让非模态对话框处于循环
14     return FALSE; //return FALSE释放线程
15 }

4.在对话框对象中进行界面线程的创建。

1 void CmfcThreadDlg::OnBnClickedOk()
2 {
3     // TODO: 在此添加控件通知处理程序代码
4     AfxBeginThread(RUNTIME_CLASS(CUIThreadApp));
5 }

 

四。线程挂起(暂停)、恢复、中止

1.SuspendThread

DWORD
WINAPI
SuspendThread(
_In_ HANDLE hThread
);

2.ResumeThread

DWORD
WINAPI
ResumeThread(
_In_ HANDLE hThread
);

 1 HANDLE hThread;
 2 void CmfcThreadDlg::OnBnClickedOk()
 3 {
 4     CWinThread* pThread = AfxBeginThread(ThreadProc, this);
 5     hThread = pThread->m_hThread; //获取线程句柄
 6 }
 7 
 8 void CmfcThreadDlg::OnBnClickedbtnsuspend()
 9 {
10     SuspendThread(hThread);
11 }
12 
13 void CmfcThreadDlg::OnBnClickedbtnresume()
14 {
15     ResumeThread(hThread);
16 }

 

3.线程退出

 

推荐阅读