MFC 的 CWinThread::P ostThreadMessage 处理器未调用
MFC's CWinThread::PostThreadMessage handler not called
我正在编写一些遗留代码,这些代码使用MFC的UI线程来实现管理器线程工作线程机制。该代码过去在MFC GUI应用程序下运行,但现在它在一个单独的dll中,并从GUI应用程序和控制台应用程序中运行。
管理器线程、工作线程和主应用程序通过线程消息进行通信(工作线程实际上不需要向管理器线程发送消息,但这是它最初实现和工作的方式,所以就这样吧)。
现在,当我从控制台应用程序运行代码时,将处理从主线程发送到管理器线程的消息,并调用我的处理程序。只有当我试图从管理器线程向工作线程发送消息时,我才会遇到问题。对PostThreadMessage
的调用成功,但从未调用处理程序。这种行为在一个普通的旧控制台应用程序和Win32控制台应用程序中都被复制了(其中包括一个带有所有MFC好东西的预编译头)。
我发现了这篇旧的Microsoft文章:http://support.microsoft.com/kb/142415但我不得不承认,我并没有真正理解它。我试图按照它的建议覆盖PreTranslateMessage
函数,并在那里显式处理我的自定义消息,但在调用PostThreadMessage
后,该函数从未被调用
我试图在下面的示例中重现这个问题,在我的示例中,甚至发送给管理器线程的消息都从未得到处理,这证实了我怀疑自己做错了什么。
编辑:我添加了缺失的InitInstance
和ExitInstance
,以重载样本代码中缺失的ManagerThread
,正如MarsRover所建议的那样,实际上ManagerThread
消息现在已经被发送,但WorkerThread
消息没有,这准确地再现了我在原始代码中遇到的问题。样本代码:
//Common.h
//update the progress message
#define WM_START_RUN (WM_USER + 1)
//update the progress message
#define WM_JOB_DONE (WM_USER + 2)
//run thread has finished
#define WM_RUN (WM_USER + 3)
// ManagerThread.h
class ManagerThread : public CWinThread
{
DECLARE_DYNCREATE(ManagerThread)
protected:
ManagerThread(){} // protected constructor used by dynamic creation
virtual ~ManagerThread();
BOOL InitInstance();
int ExitInstance();
std::vector<WorkerThread*> m_WorkerThreads;
int numOfJobs;
DECLARE_MESSAGE_MAP()
afx_msg void OnStartRun(WPARAM wParam, LPARAM lParam);
afx_msg void OnJobDone(WPARAM wParam, LPARAM lParam);
afx_msg void OnQuit(WPARAM wParam, LPARAM lParam);
};
//WorkerThread.h
class WorkerThread : public CWinThread
{
DECLARE_DYNCREATE(WorkerThread)
protected:
WorkerThread(){} // protected constructor used by dynamic creation
virtual ~WorkerThread(){}
virtual BOOL InitInstance();
virtual int ExitInstance();
public:
void SetManager(CWinThread* pManager) {m_Manager = pManager;}
void SetID(int _id) {id = _id;}
protected:
int id;
CWinThread* m_Manager;
DECLARE_MESSAGE_MAP()
afx_msg void OnRun(WPARAM wParam, LPARAM lParam);
afx_msg void OnQuit(WPARAM wParam, LPARAM lParam);
};
// ManagerThread.cpp
IMPLEMENT_DYNCREATE(ManagerThread, CWinThread)
ManagerThread::~ManagerThread() {
while(!m_WorkerThreads.empty()) {
std::vector<WorkerThread*>::iterator it = m_WorkerThreads.begin();
(*it)->PostThreadMessage(WM_QUIT, 0, 0);
m_WorkerThreads.erase(it);
}
}
BOOL CFilterManagerThread::InitInstance()
{
return CWinThread::InitInstance();
}
int CFilterManagerThread::ExitInstance()
{
return CWinThread::ExitInstance();
}
BEGIN_MESSAGE_MAP(ManagerThread, CWinThread)
ON_THREAD_MESSAGE(WM_START_RUN, OnStartRun)
ON_THREAD_MESSAGE(WM_JOB_DONE, OnJobDone)
ON_THREAD_MESSAGE(WM_QUIT, OnQuit)
END_MESSAGE_MAP()
void ManagerThread::OnJobDone( WPARAM wParam, LPARAM lParam) {
numOfJobs--;
if (!numOfJobs) {
OnQuit(0,0);
}
}
void ManagerThread::OnStartRun(WPARAM wParam, LPARAM lParam) {
numOfJobs = (int) wParam;
for (int i = 0; i < numOfJobs; i++) {
WorkerThread *newThread = (WorkerThread*)AfxBeginThread(RUNTIME_CLASS(WorkerThread), THREAD_PRIORITY_LOWEST, 0, CREATE_SUSPENDED);
newThread->SetID(i);
newThread->SetManager(this);
m_WorkerThreads.push_back(newThread);
newThread->ResumeThread();
Sleep(1000); //sleep 1 second before sending message to allow the thread to strat running
newThread->PostThreadMessage(WM_RUN, 0, 0);
}
}
void ManagerThread::OnQuit(WPARAM wParam, LPARAM lParam) {
AfxEndThread(0);
}
// WorkerThread.cpp
IMPLEMENT_DYNCREATE(WorkerThread, CWinThread)
BOOL WorkerThread::InitInstance() {
// TODO: perform and per-thread initialization here
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
return TRUE;
}
int WorkerThread::ExitInstance() {
// TODO: perform any per-thread cleanup here
//uninitialize the COM library
CoUninitialize();
return CWinThread::ExitInstance();
}
BEGIN_MESSAGE_MAP(WorkerThread, CWinThread)
ON_THREAD_MESSAGE(WM_RUN, OnRun)
ON_THREAD_MESSAGE(WM_QUIT, OnQuit)
END_MESSAGE_MAP()
void WorkerThread::OnRun(WPARAM wParam, LPARAM lParam) {
cout << id <<endl;
m_Manager->PostThreadMessage(WM_JOB_DONE, id, 0);
}
void WorkerThread::OnQuit(WPARAM wParam, LPARAM lParam) {
AfxEndThread(0);
}
在main
:中
ManagerThread *manager = (ManagerThread*)AfxBeginThread(RUNTIME_CLASS(ManagerThread), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
manager->ResumeThread();
Sleep(1000); //sleep 1 second before sending message to allow the thread to start running
manager->PostThreadMessage(WM_START_RUN, 10, 0);
while(true){}
这是一个粗略的样本。当然,在我的原始代码中,我使用了比Sleep
和while(true)
更好的机制来确保同步,并避免程序在管理器线程结束之前结束。但它再现了我所面临的问题,所以我认为没有必要再增加任何复杂性。
找出问题所在。问题出在WorkerThread::initInstance
中对CoInitializeEx
的调用上。显然,该调用在很长一段时间内阻止了线程的初始化,甚至超过了示例代码中的Sleep(1000)。因此,我在创建消息队列之前发布消息。因此,请遵循MSDN中的说明:
消息发布到的线程必须已创建消息队列,否则对PostThreadMessage的调用失败。使用以下内容处理这种情况的方法。
创建一个事件对象,然后创建线程。
使用WaitForSingleObject函数等待设置事件在调用PostThreadMessage之前,将其设置为已发出信号的状态。
在消息将发布到的线程中,调用PeekMessage作为显示在此处,以强制系统创建消息队列。
PeekMessage(&msg,NULL,WM_USER,WM_USER,PM_NOREMOVE)
设置事件,以指示线程已准备好接收已发布的消息消息。
根据前面的问题,我为每个线程类创建了一个成员CEvent
,并将InitInstance
更改为:
BOOL CFilterWorkerThread::InitInstance()
{
BOOL worked=CWinThread::InitInstance();
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
MSG msg;
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
m_ControllerThreadReady.SetEvent();
return TRUE;
}
为了在将偶数设置为true之前强制初始化消息队列。然后在ManagerThread
中,我在向WorkerThread
发布任何消息之前调用WaitForSingleObject
。
- 什么时候调用组成单元对象的析构函数
- #定义c-预处理器常量..我做错了什么
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 函数调用中参数的顺序重要吗
- OpenGL - 在抛出"__gnu_cxx::recursive_init_error"实例后终止调用?
- 预处理器:插入结构名称中的前一个行号
- 如何在c++中实现处理器调度模拟器
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 不带预处理器的调用方法/文件的文件名/行号
- 在预处理器中检查 g++ 是否使用 -fopenmp 调用
- 获取对源文件中特定函数的所有调用并生成其他文件(使用 C、C++预处理器或脚本)
- 预处理器宏调用内联函数
- MFC 的 CWinThread::P ostThreadMessage 处理器未调用
- 除了繁忙的等待之外,还有其他处理器密集度较低的方法来限制调用函数的速度吗
- 使用提升预处理器以迭代方式调用可变参数模板
- 使用预处理器宏编写另一个宏调用
- MS Visual Studio 2010 c++预处理器-如果函数在宏中定义并在其他地方调用,当未定义时是否会有任何开
- 添加预处理器#define来更改包含哪些头文件以及调用哪些函数