MFC多线程(22)
Posted 易老师
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MFC多线程(22)相关的知识,希望对你有一定的参考价值。
可以把线程看成是操作系统分配CPU时间的基本实体。系统为每一个线程分配一个CPU时间片(20毫秒左右),不停地在各个线程之间切换,某个线程只有在分配的时间片内才有对CPU的控制权。由于系统为每个线程划分的时间片很小,所以看上去好象是多个线程在同时运行。进程中的所有线程共享进程的虚拟地址空间,这意味着所有线程都可以访问进程的全局变量和资源。
MFC多线程
C++有几种开启多线程的方法,MFC中利用 AfxBeginThread 来实现多线程的创建。调用方式有两种:
1、CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );
2、CWinThread* AfxBeginThread( CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );
简而言之,第一种利用的是绑定线程函数,应用于工作线程,用于后台计算等(不带窗口),第二种则可以拥有自己的线程窗口,实现消息处理。
一、工作线程:
首先,定义线程函数,可以是全局函数或者静态函数,函数原型:
UINT Proc (LPVOID lp) // lp 用于开启线程时,参数的传递
然后,开启线程:
::AfxBeginThread(Proc ,(LPVOID)&lpData,NULL,NULL,NULL,NULL);
其中,lpData 用于传递给线程函数的参数, AfxBeginThread 创建线程后的返回值为CWinThread 的指针,可以利用该指针对线程进行一些处理(不推荐,除非有线程同步机制)。
与函数调用的最大不同是:函数调用是一种阻塞式的方式,也就是主调方需要等待被调函数的返回,而线程则是一种非阻塞的工作模式,开启新的工作线程后就执行后面的流程了。
在窗口程序中,往往将有大量耗时工作的任务交付给工作线程,这样主线程就不会被阻塞,可以及时处理用户的交互功能,避免 “卡死” 的现象。
开启的工作线程,可以从主线程中获取参数 LPVOID ,由于线程共享进程所有的资源,所以可以按约定进行各种强制转换。
工作线程启动后,将自动执行线程函数(除非创建的时候指明需要手动),线程函数执行完毕后线程就终止了。
二、窗口线程
与工作线程不同的是,创建的新线程拥有自己的窗口。
首先,生成两个类,一个是继承于 CFrameWnd 的窗口类,另外一个是继承于CWinThread 的线程类
CMyThreadWnd 头文件:
#pragma once
#include "afxwin.h"
#define WM_TEST WM_USER+1 //自定义消息,用于测试消息响应
class CMyThreadWnd :
public CFrameWnd
public:
CMyThreadWnd(void);
~CMyThreadWnd(void);
DECLARE_MESSAGE_MAP()
afx_msg LRESULT OnTest(WPARAM wParam,LPARAM lParam);
;
CMyThreadWnd CPP文件:
#include "stdafx.h"
#include "MyThreadWnd.h"
CMyThreadWnd::CMyThreadWnd(void)
CMyThreadWnd::~CMyThreadWnd(void)
BEGIN_MESSAGE_MAP(CMyThreadWnd, CFrameWnd)
ON_MESSAGE(WM_TEST,OnTest)
END_MESSAGE_MAP()
LRESULT CMyThreadWnd::OnTest(WPARAM wParam,LPARAM lParam)
LPCSTR p=(LPCSTR)wParam;
CString data=(CString)p;
CDC*dc = this->GetDC();
CRect rc;
this->GetClientRect(&rc);
dc->PatBlt(0,0,rc.right,rc.bottom,WHITENESS);
dc->TextOut(100,100,data);
this->ReleaseDC(dc);
return 0;
PS:消息循环的三个宏
DECLARE_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CMyThreadWnd, CFrameWnd)
END_MESSAGE_MAP()
可以利用VS中类向导自动添加 (随便加一个消息处理函数就有了)
CMyThread 头文件:
#pragma once
#include "afxwin.h"
#include "MyThreadWnd.h"
class CMyThread :
public CWinThread
DECLARE_DYNCREATE(CMyThread)
protected:
CMyThreadWnd *wnd;
public:
CMyThread(void);
~CMyThread(void);
virtual BOOL InitInstance();
DECLARE_MESSAGE_MAP()
afx_msg void OnTest(WPARAM wParam,LPARAM lParam);
;
动态创建宏,手动添加(否则报内存不够的错误) DECLARE_DYNCREATE
CMyThread CPP文件:
#include "stdafx.h"
#include "MyThread.h"
IMPLEMENT_DYNCREATE(CMyThread, CWinThread);
CMyThread::CMyThread(void)
wnd = new CMyThreadWnd();
CMyThread::~CMyThread(void)
BOOL CMyThread::InitInstance()
// TODO: 在此添加专用代码和/或调用基类
CWinThread::InitInstance();
wnd->Create(NULL,"我的线程窗口");
wnd->ShowWindow(SW_SHOW);
wnd->UpdateWindow();
return TRUE;
BEGIN_MESSAGE_MAP(CMyThread, CWinThread)
ON_THREAD_MESSAGE(WM_TEST,OnTest)
END_MESSAGE_MAP()
void CMyThread::OnTest(WPARAM wParam,LPARAM lParam)
LPCSTR p=(LPCSTR)wParam;
CString s;
s.Format("获取消息:%s",p);
::AfxMessageBox(s);
::PostMessage(wnd->m_hWnd,WM_TEST,wParam,lParam);
cpp文件中,IMPLEMENT_DYNCREATE 与头文件中动态创建相对应。
重写InitInstance 函数,该函数在创建线程时自动调用,返回值必须为TRUE,否则线程终止。在该函数中创建线程窗口,显示并更新窗口。OnTest函数用于响应主线程发送的 WM_TEST 消息,并且把该消息再次转发给 窗口。
调用方法,参考代码:
CWinThread *t=NULL;
t = ::AfxBeginThread(RUNTIME_CLASS(CMyThread));
LPCSTR data="Test Message";
PostThreadMessage(t->m_nThreadID,WM_TEST,(WPARAM)data,0);
由此可见,窗口线程与工作线程的区别。
然而!
工作线程也是可以拥有窗口的,不过该窗口会随工作线程的终止而销毁,另外,工作线程同样也可以处理消息。参考测试方法:
线程函数:
UINT Proc(LPVOID lp)
CMyWnd* Dlg = new CMyWnd();
Dlg->Create(NULL, "线程窗口");
Dlg->ShowWindow(SW_SHOW);
Dlg->UpdateWindow();
MSG msg;
while(::GetMessage(&msg,0,0,0))
if(msg.message == WM_LBUTTONDBLCLK)
::SendMessage(Dlg->m_hWnd,WM_LBUTTONDBLCLK,0,0);
continue;
TranslateMessage(&msg);
DispatchMessage(&msg);
return 0;
测试代码
CWinThread* th3=::AfxBeginThread(abc3,NULL,NULL,NULL,NULL,NULL);
::PostThreadMessage(th3->m_nThreadID,WM_LBUTTONDBLCLK,0,0);
需要通过SendMessage给窗口发消息(不进消息队列)
当然,以上方法比窗口线程方法复杂多了!
在多线程崩溃的 MFC 中使用 Techart activeX
【中文标题】在多线程崩溃的 MFC 中使用 Techart activeX【英文标题】:using Teechart activeX in MFC with multithreading crashed 【发布时间】:2016-04-14 08:16:25 【问题描述】:当我在MFC中使用teechart显示用户线程中的曲线时,它崩溃了。我想知道这个activeX是否可以支持多线程。
【问题讨论】:
【参考方案1】:TeeChart 不是线程安全的,因此您应该防止图表从一个线程重新绘制并同时从另一个线程修改。
【讨论】:
非常感谢。我找不到在多线程中使用 Techart 的演示。 @耶雷以上是关于MFC多线程(22)的主要内容,如果未能解决你的问题,请参考以下文章