RP4*_*RP4 3 c++ user-interface winapi asynchronous
I've got a background thread that is polling a server.
When there's data, i want to handle the data on the ui thread.
If I store the hwnd of the main window.
How can I get a particular method -- static void DataHandler(void*data) to be executed on the ui thread.
我认为创建一个传递hwnd和函数指针的计时器将起作用.
但有更好的方法吗?我可以使用postmessage以某种方式调用datahandler.
另外,我不是在编写ui代码,所以我没有能力修改消息循环中的任何内容.
Joh*_*ing 25
我经常使用两种主要方法在线程之间进行通信.
创建自定义Windows消息,ala:
#define WM_YOU_HANVE_DATA WM_USER + 101
Run Code Online (Sandbox Code Playgroud)
创建一个自定义数据类型,用于保存要发送到主线程进行处理的数据:
struct MyData
{
string client_;
string message_type_;
string payload_;
};
Run Code Online (Sandbox Code Playgroud)
从您的工作线程,实例化MyData 堆上的副本,填充它,并将其发送到主线程:
MyData* data = new MyData;
data->client_ = "hoser";
// ... etc
PostMessage(main_wnd_handle, WM_YOU_HAVE_DATA, reinterpret_cast<WPARAM>(data), );
Run Code Online (Sandbox Code Playgroud)
在主线程中,处理此消息并以适当的方式处理数据.
BEGIN_MESSAGE_MAP(MyAppWindow, CDialogEx)
// ... stuff's going to already be here
ON_MESSAGE(WM_YOU_HAVE_DATA, OnYouHaveData)
END_MESSAGE_MAP()
// ...
Run Code Online (Sandbox Code Playgroud)
一个重要的注意事项:MyAppWindow主线程现在拥有指向的内存MyData*,所以你必须拥有它的所有权.我这样做auto_ptr:
LRESULT MyAppWindow::OnYouHaveData(WPARAM wp, LPARAM )
{
auto_ptr<MyData> data(reinterpret_cast<MyData*>(wp));
DisplayeClient(data->client_);
// etc
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这可能是最简单的方法,它在线程安全的意义上也很强大.因为您将数据的所有权传递给主线程,所以没有争用.
这种方法的最大缺点是规模的限制.这依赖于Windows消息泵来在线程之间移动数据.几乎总是,这不是问题.但是Windows消息队列可以处理的消息数量有限制:
每个消息队列的发布消息数限制为10,000.
(参考)
同样,对于大多数应用来说,这没有问题.
异步过程调用(APC)是在特定线程的上下文中异步执行的函数.(链接)如果ProcessIncomingData()你想在主线程上执行一个函数,但是你想从工作线程触发它,你可以使用相当直接的方式调用该函数QueueUserAPC().
与该PostMessage()方法一样,您从在堆上实例化的自定义数据类型开始:
struct MyData
{
string client_;
string message_type_;
string payload_;
};
// ...
MyData* data = new MyData;
data->client_ = "hoser";
Run Code Online (Sandbox Code Playgroud)
定义用户APC,记住获取传入数据的所有权:
VOID CALLBACK ProcessIncomingData(ULONG_PTR in)
{
auto_ptr<MyData> data(reinterpret_cast<MyData*>(in));
// magic happens
}
Run Code Online (Sandbox Code Playgroud)
然后排队异步过程调用.使用该PostMessage()方法,您需要主线程的窗口HWND.在这里,您需要主线程的实际线程HANDLE.
HANDLE main_thread = my_thread_params.main_thread_handle_;
QueueUserAPC(ProcessIncomingData, main_thread, reinterpret_cast<ULONG_PTR>(data));
Run Code Online (Sandbox Code Playgroud)
有一个很大的警告.为了让主线程调用APC,主线程必须处于可警告的等待状态.当您将"alertable"标志设置为true 时,调用WaitEx()等WaitForMultipleObjectsEx()之一时,您将进入可警告的等待状态.
问题是GUI线程几乎从不应该处于可警告的等待状态,因为你几乎不应该等待.等待主线程将阻止消息泵,使您的应用程序似乎冻结.这真是太糟了.我将此方法包含在内以获得完整性 - 您经常需要在两个工作(非GUI)线程之间进行通信,这通常是最有效的方法.