简体   繁体   English

PostThreadMessage不起作用

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM