gpt4 book ai didi

c++ - 未调用 MFC 的 CWinThread::PostThreadMessage 处理程序

转载 作者:可可西里 更新时间:2023-11-01 11:58:34 24 4
gpt4 key购买 nike

我正在处理一些遗留代码,这些代码使用 MFC 的 UI 线程来实现管理器线程-工作线程机制。代码过去在 MFC GUI 应用程序下运行,但现在它在一个单独的 dll 中,并且可以从 GUI 应用程序和控制台应用程序运行。

管理器线程、工作线程和主应用程序通过线程消息进行通信(工作线程实际上并不需要向管理器线程发送消息,但这是它最初实现和工作的方式,所以你去吧)。

现在,当我从控制台应用程序运行代码时,会处理从主线程发送到管理器线程的消息,并调用我的处理程序。只有当我尝试从管理线程向工作线程发送消息时,我才会遇到问题。对 PostThreadMessage 的调用成功但从未调用处理程序。此行为在普通的旧式控制台应用程序和 Win32 控制台应用程序(包括带有所有 MFC 好东西的预编译 header )中重现。

我找到了这篇旧的 Microsoft 文章:http://support.microsoft.com/kb/142415但我不得不承认我并没有真正理解它。我尝试按照它的建议重写 PreTranslateMessage 函数并在那里显式处理我的自定义消息,但在调用 PostThreadMessage

后从未调用该函数

我试图在下面的示例和我的示例中重现该问题,甚至从未处理过发送给管理器线程的消息,这证实了我对我做错事的怀疑。

编辑:我添加了缺少的 InitInstanceExitInstance 来重载我的示例代码中缺少的 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){}

这是一个粗略的示例。当然,在我的原始代码中,我使用了比 Sleepwhile(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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com