我有一个事件处理线程类,它允许我从其他线程引发事件而不中断它们的操作。当调用析构函数时,我向线程发送一条退出消息,但它的消息循环似乎没有收到这条消息。
#include <iostream>
using namespace std;
#include <windows.h>
#define WIN32_LEAN_AND_MEAN
#define ET_EVENTPUSH 7854
#define ET_QUITLOOP 6581
#define EVENT_HANDLER void
typedef void (*EVENT)(LPVOID);
//# event handler thread
class event_thread
{
private:
//vars
HANDLE m_thread; //event loop thread
DWORD m_id; //thread id
//thread procedure
static DWORD WINAPI listener_loop(LPVOID);
public:
//constructor
event_thread();
~event_thread();
//functions
void push_event(EVENT, LPVOID);
};
//# event handler thread
event_thread::event_thread()
{
//create thread
m_thread = CreateThread(NULL, 0, listener_loop, NULL, 0, &m_id);
}
event_thread::~event_thread()
{
DWORD dw;
//stop thread
if (m_thread)
{
dw = GetLastError();
PostThreadMessage(m_id, ET_QUITLOOP, 0, 0);
dw = GetLastError();
WaitForSingleObject(m_thread, INFINITE);
CloseHandle(m_thread);
}
}
void event_thread::push_event(EVENT e, LPVOID p)
{
PostThreadMessage(m_id, ET_EVENTPUSH, (UINT)e, (UINT)p);
}
DWORD WINAPI event_thread::listener_loop(LPVOID param)
{
MSG msg;
#define event_type msg.message
#define event_call ((EVENT)(msg.wParam))
#define event_param (LPVOID)(msg.lParam)
//while thread is alive
while (GetMessage(&msg, NULL, 0, 0))
{
switch (event_type)
{
case ET_EVENTPUSH:
event_call(event_param);
break;
case ET_QUITLOOP:
return 0;
}
}
return 0;
}
EVENT_HANDLER asda(LPVOID as)
{
cout << (int)as << endl;
}
int main()
{
event_thread thr;
int i = 1;
while (!GetAsyncKeyState(VK_NUMPAD1))
{
thr.push_event(asda, (LPVOID)(i++));
Sleep(20);
}
return 0;
}
当我发送退出消息时,GetMessage
没有返回。在 PostThreadMessage
调用之后使用 GetLastError()
会得到 1444 ERROR_INVALID_THREAD_ID
。
我不想使用 PeekMessage
,因为它使用 100% CPU,也不想使用 Sleep
,因为这显然是不好的做法。 p>
谢谢
最佳答案
ERROR_INVALID_THREAD_ID
表示您试图将消息发布到没有消息队列的线程 ID。因此,您要么在线程消息循环运行之前尝试发布,要么在线程已经终止之后尝试发布。
当你的线程开始运行时,它应该首先向自己发送消息以创建一个消息队列,然后设置一个信号来表明它已准备好接收消息,最后进入它的消息循环。在您的类构造函数中,在调用 CreateThread()
之后,它可以在退出之前等待该信号。
试试这个:
#include <iostream>
using namespace std;
#include <windows.h>
#define WIN32_LEAN_AND_MEAN
#define ET_START WM_USER+1
#define ET_EVENTPUSH WM_USER+2
#define ET_QUITLOOP WM_USER+3
#define EVENT_HANDLER void
typedef void (*EVENT)(LPVOID);
//# event handler thread
class event_thread
{
private:
//vars
HANDLE m_thread; //event loop thread
DWORD m_id; //thread id
bool m_ready; // message queue is ready
//thread procedure
static DWORD WINAPI listener_loop(LPVOID);
public:
//constructor
event_thread();
~event_thread();
//functions
bool push_event(EVENT, LPVOID);
};
//# event handler thread
event_thread::event_thread()
{
//create thread
m_ready = false;
m_thread = CreateThread(NULL, 0, &listener_loop, this, 0, &m_id);
if (m_thread)
{
while (!m_ready)
Sleep(10);
}
}
event_thread::~event_thread()
{
//stop thread
if (m_thread)
{
if (!PostThreadMessage(m_id, ET_QUITLOOP, 0, 0))
{
DWORD dw = GetLastError();
...
}
WaitForSingleObject(m_thread, INFINITE);
CloseHandle(m_thread);
}
}
bool event_thread::push_event(EVENT e, LPVOID p)
{
return PostThreadMessage(m_id, ET_EVENTPUSH, (WPARAM)e, (LPARAM)p);
}
DWORD WINAPI event_thread::listener_loop(LPVOID param)
{
event_thread *pThis = (event_thread*)param;
MSG msg;
#define event_type msg.message
#define event_call ((EVENT)(msg.wParam))
#define event_param (LPVOID)(msg.lParam)
PostThreadMessage(pThis->m_id, ET_START, 0, 0);
pThis->m_ready = true;
//while thread is alive
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
switch (event_type)
{
case ET_EVENTPUSH:
event_call(event_param);
break;
case ET_QUITLOOP:
PostQuitMessage(0);
break;
}
}
return 0;
}
如果您不喜欢 Sleep()
循环,您可以将 m_ready
替换为可等待事件,然后使用 SetEvent()
和WaitForSingleObject()
。
关于c++ - PostThreadMessage 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22428066/