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

标签 c++ user-interface winapi asynchronous

我有一个正在轮询服务器的后台线程。当有数据时,我想在 UI 线程上处理数据。如果我存储主窗口的hwnd

如何让特定方法 static void DataHandler(void* data) 在 UI 线程上执行?

我认为创建一个传递 hwnd 和函数指针的计时器会起作用。但是有更好的方法吗?我可以使用 PostMessage 以某种方式调用数据处理程序吗?

此外,我没有编写 UI 代码,因此我无法修改消息循环中的任何内容。

最佳答案

我最常使用两种主要方法在线程之间进行通信。

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), );

在主线程中,以任何合适的方式处理这个消息和数据。

BEGIN_MESSAGE_MAP(MyAppWindow, CDialogEx)
        // ...  stuff's going to already be here
        ON_MESSAGE(WM_YOU_HAVE_DATA, OnYouHaveData)
END_MESSAGE_MAP()

// ...

重要说明:MyAppWindow 的主线程现在拥有 MyData* 指向的内存,因此您必须取得所有权它的。我在此处使用 auto_ptr 执行此操作:

LRESULT MyAppWindow::OnYouHaveData(WPARAM wp, LPARAM )
{
  auto_ptr<MyData> data(reinterpret_cast<MyData*>(wp));
  DisplayeClient(data->client_);
  // etc
  return 0;  
}

这可能是最简单的方法,而且在线程安全的意义上也很健壮。因为您将数据的所有权传递给了主线程,所以没有争用。

这种方法的最大缺点是规模限制。这依赖于 Windows 消息泵在线程之间移动数据。几乎总是,这不是问题。但是 Windows 消息队列可以处理的消息数量是有限制的:

There is a limit of 10,000 posted messages per message queue.

( reference )

同样,对于大多数应用程序来说,这不是问题。

2) 队列用户APC()

异步过程调用 (APC) 是在特定线程的上下文中异步执行的函数。 ( Link ) 如果有一个函数 ProcessIncomingData() 你想在主线程上执行,但你想从工作线程触发它,你可以相当直接地调用该函数使用 QueueUserAPC() 的方式。

PostMessage() 方法一样,您从在堆上实例化的自定义数据类型开始:

struct MyData
{
  string client_;
  string message_type_;
  string payload_;
};

// ...

MyData* data = new MyData;
data->client_ = "hoser";

定义用户 APC,记住获取传入数据的所有权:

VOID CALLBACK ProcessIncomingData(ULONG_PTR in)
{
  auto_ptr<MyData> data(reinterpret_cast<MyData*>(in));
  // magic happens
}

然后您将异步过程调用排队。使用 PostMessage() 方法,您需要主线程的窗口 HWND。在这里,您需要主线程的实际线程 HANDLE。

HANDLE main_thread = my_thread_params.main_thread_handle_;
QueueUserAPC(ProcessIncomingData, main_thread, reinterpret_cast<ULONG_PTR>(data));

有一个重要警告。为了让您的 APC 被主线程调用,主线程必须处于 alertable 等待状态。当您调用 WaitEx() 函数之一(例如 WaitForMultipleObjectsEx())时,您进入了可警告的等待状态。将“alertable”标志设置为 true。

问题是 GUI 线程几乎不应该处于可警告的等待状态,因为您几乎不应该等待。在主线程中等待会阻塞消息泵,使您的应用程序看起来像死机一样。这真是太糟了。为了完整起见,我包括了这个方法——您经常需要在两个工作线程(非 GUI)之间进行通信,这通常是最有效的方法。

关于c++ - 由于后台线程上的事件,在 ui 线程上执行方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3783713/

相关文章:

python - 用于 Windows 的 socket.fromfd

javascript - Emscripten 未优化

c++ - 为什么 printf 不在这里打印?

python - GTK 是否有通用更新通知/发布子系统?

objective-c - 在 iPhone 应用程序中动态更改 UI

c++ - 在 Win32 中从字符串中解析日期

c++ - segmentation violation Segmentation fault c++ 分子数组中的值

c++ - 从 cv::connectedComponents 访问标记区域

c# - Windows 7 上的 IIS 7 中是否有管理服务 (WMSVC) UI?

c++ - 不同配置单元之间的注册表符号链接(symbolic link)