windows线程间同步方式
- PostMessage、SendMessage、PostThreadMessage方式
- Event方式,SetEvent、ResetEvent、WaitForMultipleObjects
- 临界区
- 信号量
子线程与主线程之间的异步、同步回调方式
借助windows窗口,在主线程中注册回调事件,子线程通过postmessage方式发送给该窗口,从而实现消息通知。
实现方式如下:
1.在主线程中创建一个窗口,在窗口WndClass中回调函数设置指定的消息通知WM_USER_NOTIFY
伪代码如下:
Class MainSuperviseWnd {
WNDCLASS wndclass;
wndclass.lpfnWndProc=WndProc; //定义窗口处理函数
wndclass.hInstance=hInstance; //hInstance为主线程句柄,或用module{0}代替
if(!RegisterClass(&wndclass)) //如果注册失败 发出警告
return FALSE;
hwnd=CreateWindow( lpszClassName,
lpszTitle,
WS_OVERLAPPEDWINDOW,
0,0,0,0,NULL,NULL,
hInstance,
this);
};
其中回调函数为:
UINT CALLBACK WNDPROC(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch(msg):
case WM_USER_NOTIFY:
{
// OnDispatch Method
OnDispatch(wParam, lParam);
}
}
在子线程中使用异步分发函数
void DispatchOnMain(){
::PostMessage(hWnd, WM_USER_NOTIFY, wParam, lParam);
}
或者在子线程中使用同步分发函数并设置超时时间
void DispatchSyncOnMain() {
::SendMessage(hWnd, WM_USER_NOTIFY, wParam, lParam);
::WaitForSingleObject(
}
当然,跨线程调用除了同步或异步执行一些常见操作外,还可以带上lambd表达式
异步或同步跨线程执行回调函数
比较理想的方式是使用QT的emit\signal\slot方式,相对来说线程安全也十分灵活,而且设置的参数是可变的。但是在一般win32应用上,要复制QT的实行难度比较大,我们选择轻量级的实现方式。
一般来说,线程上的函数调用是在栈上,lambda表示式作为闭包同样也在线程上,所以lambda表示如果要传递给其他线程,可以考虑借助堆来实现。
我们可以再SendMessage之前使用new方式在堆上创建一个闭包
void DispatchOnMain(const std::function<void(void)>& func){
std::function<void(void)> *p = new std::function<void(void)>(func);
::PostMessage(hwnd, WM_USER_NOTIFY,wParam,(LPVOID)p);
}
相对应的,在消息处理函数中处理回调函数
void OnDispatch(WPARAM wParam, LPARAM lParam){
std::function<void(void)> *block = reinterpret_cast<std::function<void(void)>>(lParam);
if(block){
(*block)();
delete block;
}
}
以上及实现了子线程同步回调函数到主线程中的方式。
相对于ios的GCD方式而言,该方法比较简陋,而且也只有一种同步方式,当时可以适当拓展。比如使用广播的方式来通知所有当前能够处理WM_USER_NOTIFY的消息窗口。