Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 由于后台线程上的事件,在ui线程上执行方法_C++_User Interface_Winapi_Asynchronous - Fatal编程技术网

C++ 由于后台线程上的事件,在ui线程上执行方法

C++ 由于后台线程上的事件,在ui线程上执行方法,c++,user-interface,winapi,asynchronous,C++,User Interface,Winapi,Asynchronous,我有一个后台线程正在轮询服务器。当有数据时,我希望在UI线程上处理数据。如果我存储主窗口的hwnd 如何在UI线程上执行特定的方法静态void DataHandler(void*data) 我认为创建一个通过hwnd和函数指针的计时器是可行的。但是有更好的办法吗?我可以使用PostMessage以某种方式调用datahandler吗 另外,我没有编写UI代码,因此我无法修改消息循环中的任何内容。您可以做的一件事是使用线程间信号对象,可能与布尔标志一样简单。当数据出现在服务器轮询线程上时,可以向该

我有一个后台线程正在轮询服务器。当有数据时,我希望在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));