文档库 最新最全的文档下载
当前位置:文档库 › MFC线程简述

MFC线程简述

MFC线程简述
MFC线程简述

MFC线程简述:

MFC中存在三种线程:

A、Ui线程:通过创建窗口得到,具备标准窗口的功能。

B、工作者线程:通过CreateThread函数直接创建,不具备消息队列。

C、带消息队列的工作者线程:通过继承CWinThread得到,具备消息队列。

A种和C种线程使用消息队列,对于使用者来说,这两种线程需要自己本身或其他线程向其发送消息,才进行相应工作,否则保持静默状态,该两种线程擅长实时处理外部信号。

B种线程不使用消息队列,可以用单个函数作为其线程的本体,适合处理步骤相对固定的算法。

线程间通信的方式:

方式一:全局变量,各线程通过修改全局变量传递信息,通过循环检测查看信息。

方式二:消息传递,通过windows消息机制传递。

方式一问题主要有两个:第一是全局变量过多,不便于管理;第二个是循环检测过于缓慢,并且较不灵活,不能够迅速响应变化。

因此,只有B类型,工作者线程适合使用方式一,其实现也相对简单,下面给出例子:

MyThread.h

class MyThread

{

public:

MyThread();

~MyThread();

void start(); //启动线程

void setThreadNumber(int); //设置线程标识号

protected:

static DWORD WINAPI run(LPVOID lpPram); //线程本体

private:

struct Data

{

int threadNum;

} data; //线程私有变量,每个线程都有独立的data

LPVOID lpData; //线程私有变量的指针

static int cnt; //该类型线程的一个静态(类似全局)变量,该类产生的线程共用

static HANDLE hMutexCnt; //静态变量cnt关联的互斥对象,用于协调各线程对cnt的访问。

};

MyThread.cpp

//注意静态变量需作为全局变量声明,如下

int MyThread::cnt = 100;

HANDLE MyThread::hMutexCnt = CreateMutex(NULL, FALSE, NULL);

//---------------- public ------------------

MyThread::MyThread()

{

this->lpData = (LPVOID)&this->data; //初始化私有变量的指针

}

MyThread::~MyThread()

{

}

void MyThread::start()

{

HANDLE hThread = CreateThread(NULL, 0, MyThread::run, this->lpData, 0, NULL);

CloseHandle(hThread); //注意此处并不是杀死线程,而是关闭其句柄(因为现在暂不需要),当线程自行结束后系统会释放句柄。

}

void MyThread::setThreadNumber(int threadNum)

{

this->data.threadNum = threadNum;

}

//--------------- protected -----------------

DWORD WINAPI MyThread::run(LPVOID lpPram)

{

MyThread::Data *tpData = (MyThread::Data *)lpPram; //注意与CreateThread处比较,lpPram其实就是this->lpData,之所以要传递指针是因为静态函数是该类所有对象的公有成员,不能通过this来指定成员变量。

cout << "Thread " << tpData->threadNum << " is running\n" << endl;

while (true) //循环

{

if (MyThread::cnt > 0)

{

WaitForSingleObject(MyThread::hMutexCnt, INFINITE); //检查是否有其他的

线程在使用cnt,如有,等待,无,则抢占cnt的使用权。

cout << "Thread " << tpData->threadNum << " : " << MyThread::cnt-- << endl;

ReleaseMutex(MyThread::hMutexCnt); //释放cnt的使用权。

}

else

{

WaitForSingleObject(MyThread::hMutexCnt, INFINITE);

cout << "None.\n" << endl;

ReleaseMutex(MyThread::hMutexCnt);

break; //当cnt减到为0的时候,退出循环。

}

}

return 0; //函数返回,线程结束,自行退出,并释放作用域内的所有变量占用的内存。}

在使用的地方:

MyThread thread1, thread2; //新建两个MyThread类型的线程

thread1.setThreadNumber(1); //设置线程标号

thread2.setThreadNumber(2);

thread1.start(); //启动线程,但不需要关闭,自行关闭。

thread2.start();

可以观察这两个线程是如何工作的。

需要注意的地方:工作者线程必须能自行退出,不推荐使用TerminateThread函数强行中止线程,因为这样会导致线程占用的内存无法释放。

方式二,分两种情况。

情况1:UI线程

在UI线程的h文件开头,添加以下代码:

#define WM_MY_MESSAGE (WM_USER+100)

定义WM_MY_MESSAGE的消息ID,+100是为了回避某些ActiveX控件占用的消息ID

在UI线程的h文件的类声明中,添加以下代码:

protected:

afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);

该函数作为MY_MESSAGE消息的响应函数,具有两个外部输入参数(指针)。

在UI线程的cpp处,在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP()之间,添加:

ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage)

这样就将WM_MY_MESSAGE和OnMyMessage(WPARAM wParam, LPARAM lParam)连接起来了

定义函数OnMyMessage

LRESULT CThreadMsgDemoDlg::OnMyMessage(WPARAM wParam, LPARAM lParam)

{

MessageBox(L"WM_MY_MESSAGE");

return 0;

}

因此当WM_MY_MESSAGE被触发后,会弹出窗口显示"WM_MY_MESSAGE"

在主窗口添加一个按钮,在按钮的响应函数中:

::PostMessage(this->m_hWnd, WM_MY_MESSAGE, NULL, NULL);

第一个参数是目标的句柄,填入当前窗口的句柄;第二个参数是发送的消息,填入WM_MY_MESSAGE;第三四个参数是消息携带的数据,我们的消息不需要数据,因此是两个NULL

编译程序,点击按钮,若成功,将弹出WM_MY_MESSAGE。

由于这是消息机制,而不是变量或指针,所以,无论任何程序程序向该UI线程发送WM_MY_MESSAGE,那么该窗口都会响应。

情况2:带消息队列的工作者线程。

MyThread.h

#define WM_MY_THREAD_MESSAGE (WM_USER+101) //定义消息ID

class MyThread :

public CWinThread

{

DECLARE_DYNCREATE(MyThread) //使能动态创建,不需要懂其原理,该类进行线程化时必须有此声明。

public:

CWinThread *m_pThrd = NULL; //控制CWinThread线程的指针,用以获取句柄或发送消息。

MyThread();

~MyThread();

virtual BOOL InitInstance(); //CWinThread线程的Run用作消息循环,不能重载,故用该成员函数初始化自身数据。

virtual int ExitInstance(); //CWinThread线程用该函数处理线程结束后残余的数据。

void start();

void stop(); //停止线程的函数与普通工作者线程不一样

void SendMsg();

protected:

afx_msg void OnThreadMessage(WPARAM wParam, LPARAM lParam); //消息响应函数DECLARE_MESSAGE_MAP() //消息声明,表示该类具有消息机制

};

MyThread.cpp

#include "MyThread.h"

IMPLEMENT_DYNCREATE(MyThread, CWinThread) //呼应DECLARE_DYNCREATE

MyThread::MyThread()

{

}

MyThread::~MyThread()

{

this->stop();

}

//注意以下信息声明不是自动生成的,要手动输入

BEGIN_MESSAGE_MAP(MyThread, CWinThread)

ON_THREAD_MESSAGE(WM_MY_THREAD_MESSAGE, OnThreadMessage)

END_MESSAGE_MAP()

void MyThread::start()

{

this->m_pThrd = AfxBeginThread(RUNTIME_CLASS(MyThread)); //注意!

}

void MyThread::stop()

{

if (this->m_pThrd == NULL)

return; //该类线程响应速度比UI线程更快,因此比较捉摸不定,程序关闭时也许自己就先行退出了,一定要检测一下。

HANDLE hThrd = this->m_pThrd->m_hThread;

if (hThrd)

{

this->m_pThrd->PostThreadMessage(WM_QUIT, NULL, NULL); //注意,是这样关闭的!

WaitForSingleObject(this->m_pThrd->m_hThread, INFINITE); //等待线程结束}

this->m_pThrd = NULL;

}

BOOL MyThread::InitInstance()

{

// TODO: 在此添加专用代码和/或调用基类

return true; //注意这里!不要用CWinThread:: InitInstance()!!否则将作为普通线程启动!

}

int MyThread::ExitInstance()

{

// TODO: 在此添加专用代码和/或调用基类

return CWinThread::ExitInstance();

}

void MyThread::SendMsg()

{

if (this->m_pThrd)

{

this->m_pThrd->PostThreadMessage(WM_MY_THREAD_MESSAGE, NULL, NULL); //

发消息的方法与UI不一样!

}

}

void MyThread::OnThreadMessage(WPARAM wParam, LPARAM lParam)

{

::AfxMessageBox(L"WM_MY_THREAD_MESSAGE");

}

相关文档