[英]PostThreadMessage doesn't work
I have an event-handling thread class which allows me to raise events from other threads without interrupting their operation. 我有一个事件处理线程类,它允许我从其他线程引发事件而不会中断它们的操作。 When the destructor is called I send a quit message to the thread, but its message loop doesn't seem to receive this message. 当析构函数被调用时,我向该线程发送一个退出消息,但它的消息循环似乎没有收到此消息。
#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
doesn't return when I send a quit message. 发送退出消息时, GetMessage
不会返回。 And using GetLastError()
after the PostThreadMessage
call gives 1444 ERROR_INVALID_THREAD_ID
. 在PostThreadMessage
调用之后使用GetLastError()
给出1444 ERROR_INVALID_THREAD_ID
。
I don't want to use PeekMessage
because it uses 100% CPU, nor Sleep
'cos it's apparently bad practice . 我不想使用PeekMessage
因为它使用100%CPU,也不想Sleep
因为它显然是不好的做法 。
Thanks 谢谢
ERROR_INVALID_THREAD_ID
means you tried to post a message to a thread ID that does not have a message queue. ERROR_INVALID_THREAD_ID
表示您尝试将消息发布到没有消息队列的线程ID。 So either you tried to post before the thread message loop was running, or after the thread had already terminated. 所以要么你试图在线程消息循环运行之前发布,要么在线程已经终止之后发布。
When your thread starts running, it should post a message to itself first to create a message queue, then set a signal to indicate that it is ready to receive messages, then finally enter its message loop. 当你的线程开始运行时,它应首先向自己发布消息以创建消息队列,然后设置一个信号以指示它已准备好接收消息,然后最终进入其消息循环。 In your class constructor, after calling CreateThread()
, it can wait for that signal before then exiting. 在类构造函数中,在调用CreateThread()
,它可以在退出之前等待该信号。
Try this: 尝试这个:
#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;
}
If you do not like the Sleep()
loop you can replace m_ready
with a waitable event, and then use SetEvent()
and WaitForSingleObject()
. 如果您不喜欢Sleep()
循环,可以将m_ready
替换为可等待的事件,然后使用SetEvent()
和WaitForSingleObject()
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.