C++ 由于后台线程上的事件,在ui线程上执行方法
我有一个后台线程正在轮询服务器。当有数据时,我希望在UI线程上处理数据。如果我存储主窗口的C++ 由于后台线程上的事件,在ui线程上执行方法,c++,user-interface,winapi,asynchronous,C++,User Interface,Winapi,Asynchronous,我有一个后台线程正在轮询服务器。当有数据时,我希望在UI线程上处理数据。如果我存储主窗口的hwnd 如何在UI线程上执行特定的方法静态void DataHandler(void*data) 我认为创建一个通过hwnd和函数指针的计时器是可行的。但是有更好的办法吗?我可以使用PostMessage以某种方式调用datahandler吗 另外,我没有编写UI代码,因此我无法修改消息循环中的任何内容。您可以做的一件事是使用线程间信号对象,可能与布尔标志一样简单。当数据出现在服务器轮询线程上时,可以向该
hwnd
如何在UI线程上执行特定的方法静态void DataHandler(void*data)
我认为创建一个通过hwnd
和函数指针的计时器是可行的。但是有更好的办法吗?我可以使用PostMessage
以某种方式调用datahandler吗
另外,我没有编写UI代码,因此我无法修改消息循环中的任何内容。您可以做的一件事是使用线程间信号对象,可能与布尔标志一样简单。当数据出现在服务器轮询线程上时,可以向该标志发送信号。您可以在UI线程的消息循环中检查此标志。或者,您可以只向UI线程发送一条自定义窗口消息
现在我重读了你的问题——因为你不能更改UI代码,所以这种方法不起作用。您可以使用WIN32 API添加自己的自定义消息挂钩函数来解决此问题。我最常用的两种方法是在线程之间进行通信 1) PostMessage() 创建自定义windows消息,ala:
#define WM_YOU_HANVE_DATA WM_USER + 101
创建一个自定义数据类型,用于保存要发送到主线程进行处理的数据:
struct MyData
{
string client_;
string message_type_;
string payload_;
};
从工作线程中,实例化堆上的MyData
副本,填充它,并将其发送到主线程:
MyData* data = new MyData;
data->client_ = "hoser";
// ... etc
PostMessage(main_wnd_handle, WM_YOU_HAVE_DATA, reinterpret_cast<WPARAM>(data), );
一个重要提示:MyAppWindow
的主线程现在拥有MyData*
指向的内存,因此您必须拥有它。我使用auto\u ptr
在此处执行此操作:
LRESULT MyAppWindow::OnYouHaveData(WPARAM wp, LPARAM )
{
auto_ptr<MyData> data(reinterpret_cast<MyData*>(wp));
DisplayeClient(data->client_);
// etc
return 0;
}
定义用户APC,记住获取传入数据的所有权:
有一个很大的警告。为了让主线程调用APC,主线程必须处于可警报的等待状态。当您调用其中一个WaitEx()函数时,例如当“alertable”标志设置为true时,您将进入可警报的等待状态
问题是GUI线程几乎永远不应该处于可警报的等待状态,因为您几乎永远不应该等待。在主线程中等待将阻塞消息泵,使应用程序看起来冻结。这很糟糕。我使用这个方法是为了完整性——您通常需要在两个工作线程(非GUI)之间进行通信,这通常是最有效的方法。我使用的方法(需要修改UI线程,但我认为所有方法在某些方面都会)是定义自定义消息ID,该ID在UI线程中处理。消息格式和处理封装在一个类中,因此主UI线程只需将消息转发给类处理程序,而不需要知道特定的格式是什么
之后,只需封装任意函数调用(我使用动态分配的boost::function对象,但还有其他选项),将其传递给带有自定义消息ID的主窗口线程,就可以在主线程的上下文中调用处理程序。如您所述,具有自定义消息部分的详细信息;只要确保传递的任何数据/对象都是在堆上分配的,如果是异步调用(例如:PostMessage),则在处理程序函数中释放
更新:John在选项1中所说的,除了在UI中由处理程序调用的函数中编写处理程序操作,因此对UI代码的影响最小,并且如果以任何方式更改要传递的数据结构,则不需要更新UI代码。这是我唯一的补充建议
希望能有所帮助。谢谢!这就是我要读的,对吗?是的,没错。其他答案也很有用,但据我所知,除非你添加一个钩子,否则它们不会起作用。
LRESULT MyAppWindow::OnYouHaveData(WPARAM wp, LPARAM )
{
auto_ptr<MyData> data(reinterpret_cast<MyData*>(wp));
DisplayeClient(data->client_);
// etc
return 0;
}
struct MyData
{
string client_;
string message_type_;
string payload_;
};
// ...
MyData* data = new MyData;
data->client_ = "hoser";
VOID CALLBACK ProcessIncomingData(ULONG_PTR in)
{
auto_ptr<MyData> data(reinterpret_cast<MyData*>(in));
// magic happens
}
HANDLE main_thread = my_thread_params.main_thread_handle_;
QueueUserAPC(ProcessIncomingData, main_thread, reinterpret_cast<ULONG_PTR>(data));