- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在处理一些遗留代码,这些代码使用 MFC 的 UI 线程来实现管理器线程-工作线程机制。代码过去在 MFC GUI 应用程序下运行,但现在它在一个单独的 dll 中,并且可以从 GUI 应用程序和控制台应用程序运行。
管理器线程、工作线程和主应用程序通过线程消息进行通信(工作线程实际上并不需要向管理器线程发送消息,但这是它最初实现和工作的方式,所以你去吧)。
现在,当我从控制台应用程序运行代码时,会处理从主线程发送到管理器线程的消息,并调用我的处理程序。只有当我尝试从管理线程向工作线程发送消息时,我才会遇到问题。对 PostThreadMessage
的调用成功但从未调用处理程序。此行为在普通的旧式控制台应用程序和 Win32 控制台应用程序(包括带有所有 MFC 好东西的预编译 header )中重现。
我找到了这篇旧的 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 中的说明进行操作:
The thread to which the message is posted must have created a message queue, or else the call to PostThreadMessage fails. Use the following method to handle this situation.
Create an event object, then create the thread.
Use the WaitForSingleObject function to wait for the event to be set to the signaled state before calling PostThreadMessage.
In the thread to which the message will be posted, call PeekMessage as shown here to force the system to create the message queue.
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE)
Set the event, to indicate that the thread is ready to receive posted messages.
从这个previous question ,我为每个线程类创建了一个成员 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;
}
为了强制消息队列在我设置even为true之前被初始化。然后在 ManagerThread
中调用 WaitForSingleObject
,然后再将任何消息发布到 WorkerThread
。
关于c++ - 未调用 MFC 的 CWinThread::PostThreadMessage 处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12764300/
所以我正在深入研究 MFC 的世界,特别是自定义使用 CWinThread 来实现辅助线程。我已经通过其他方式成功实现了工作线程,因此将 CWinThread 用于工作线程的主要动机是利用消息映射。
我有一个非常简单的问题,关于 CWinThread 如何工作以及每次调用 ResumeThread() 时入口点在哪里。我正在寻找一个看起来类似于“主”函数的条目,我可以在其中执行一些操作和分支。 我
我有这样的代码 X *m = new X(); // X - class derived from CWinThread; m->CreateThread(CRREATE_THREAD); m->b_
如您所知,可以在 MFC UI 线程中指定 OnIdle。详情可以看这篇引用http://msdn.microsoft.com/en-us/library/1sa2f19f.aspx .但我不确定如何
我有一个 C++ 应用程序 (VS2008),我这样启动线程: CWinThread *myThread= AfxBeginThread(myOp,0); 现在我要做的就是给这个线程命名,这样我就可以
我正在使用 MFC C++,我正在尝试使用来自 Dlg 类的 PostThreadMessage 将消息发送到 CWinThread,但该消息未在线程类上处理 线程的.H文件: #define
当我调试用 C++ 开发的 Windows 应用程序时,我发现这个函数调用 CWinThread::PumpMessage()。我读过 MSDN以及其他一些要了解的论坛帖子。但仍然不确定它的作用。 有
在我的项目中,我有管理类和计算类。从 CWinThread 派生的 calc 类。和 manager 有一个指向 calc 类的指针。我如何使用 AfxBeginThread 以及在哪里使用?请注意,
我有一个通过 AfxBeginThread 生成线程的循环,它将 CWinThread 指针存储在一个数组中。在每次迭代中,我检查线程是否为空并将线程的句柄存储在另一个数组中。 const unsig
我正在尝试在名为 ClientManager 的类中创建工作线程,但我无法从新的 CWinThread 访问 AfxGetMainWnd(),即: UINT ClientManager::Worker
我正在使用 AfxBeginThread 启动一个线程。这将返回一个指向新的 CWinThread 对象的指针。 MSDN 声明此指针为 NULL,如果线程创建失败,它将释放所有内容。但是,一旦线程在
我正在调用 AfxBeginThread 并使用 CWinThread 在我的 MFC 应用程序中启动一个 UI 线程。 我注意到,如果我的主线程在 CWinThread::InitInstance(
我想知道在 MFC 中使用 CWinThread 派生类作为工作线程的过程是什么。 msdn 文档说 CWinthread::InitInstance() 或 CWinthread::Run() 应该
我正在处理一些遗留代码,这些代码使用 MFC 的 UI 线程来实现管理器线程-工作线程机制。代码过去在 MFC GUI 应用程序下运行,但现在它在一个单独的 dll 中,并且可以从 GUI 应用程序和
我是一名优秀的程序员,十分优秀!