作者cole945 (躂躂..)
看板C_and_CPP
标题Re: [讨论] WINAPI 执行绪问题
时间Thu Oct 19 00:33:39 2017
※ 引述《eric231 (嘻嘻雷梦)》之铭言:
: 各位大大好
: 目前有一个command line下的USB测试程式
: 用winapi 的方式画出一个UI
: 功能需求是想用本来在main loop 底下跑的function然後去
: 侦测event然後即时显示在listbox上
: 请问是不是需要另外用 winapi create一个tread去run本来
: main loop 底下跑的function?
: 附上程式码
: https://ideone.com/3lDWUG
你没有描述要怎样侦测 event, 就先简设是大概是
event =
tcx_GetEvent(u8_Port) 吧
一般 IO 分两种情况
1. blocking
2. non-blocking
(3. asynchronous 这种先不管, 你应该暂时不会用到,
但这其实才是 event-driven 下最常见的用法)
blocking 就是 tcx_GetEvent 一定要得到一个 event 或 error,
如果没 event 就卡住, 所以叫 blocking. 这是最单纯最常见的用法
这种 case 一定要 CreateTherad, 不然 UI 卡住滑鼠点下去不理你,
然後就会跳出 程式没有回应
non-blocking 就是 call 会立即传回, 如果没东西就回无.
如果是这种 case, 其实也不用 CreateThread 了.
因为没意外的话, 你的 thread function 大概也是
while (1) {
event = tcx_GetEvent(u8_Port);
// 处理 event
sleep (TIME_FOR_NEXT_EVENT);
}
那不如直接 set timer 用原本的 message loop 来处理就好了, 反而还
简单俐落些. 当然, 若要处理的事很多而影响到处理其他 UI 讯息的话,
也可以开一条 thread 来处理
以 event-driven programming 的惯用流程就是
1. 开一个 worker thread
2. 在 worker thread 里处理工作
3. 更新 UI
看推文你应该对 UI 基本概念都有了, 应该只是 WinAPI 不熟不知道怎麽更新 UI?
基本上 UI 不是 thread-safe, 所以不能直接从 worker thread 操作 listbox.
惯用方法就是丢一个 message 回 UI thread 的 message queue.
而在 WinAPI 就是用 SendMessage 或 PostMessage 丢
SendMessage/PostMessage 四个参数
1. Window handle
2. Message
3. wParam
4. lParam
Window handle 是用来指定要丢进去的 message queue, 因为要丢回原本的
UI thread, 所以是填一开始 CreateWindow 的得到的 handle
Message 是想丢进去的 message, 这里应该自订一个 USB event
例如 #define WM_MY_TCX_EVENT (WM_USER+1)
wParam 和 lParam 是两个额外要和这个 event 一起丢给 message queue 的参数
他们的 size 都应至少够装一个 poiter
https://msdn.microsoft.com/en-us/library/aa383751(VS.85).aspx
以上整合起来, 在 worker thread 那端大致是这样
while (!quit) {
event = tcx_GetEvent(u8_Port);
if (event == -1)
ExitThread(-1);
else
SendMessage(hwnd, WM_MY_TCX_EVENT, event, 0);
// get next usb event
}
ExitThread(0);
而 UI 那端则是
WndProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam) {
...
switch (uMsg) {
case WM_MY_TCX_EVENT:
// 处理 wParam 传来的 event
break;
}
}
另外有一些 thread synchonization 的要注意一下.
SendMessage 一般比较常用, 而他和 PostMessage 的差别是,
SendMessage 会等待该 message 被处理完才 return,
但 PostMessage 丢了就 return 了. 示意流程是这样
UI Worker
| |
| tcx_GetEvent
|<------------ SendMessage
WinProc
WM_MY_TCX_EVENT
|
------------------|
| tcx_GetEvent
|<------------ SendMessage
WinProc
WM_MY_TCX_EVENT
...
|
当 worker thread 卡着时, UI thread 还是可以处理其他 event,
但 SendMessage 会卡住等待 message 被处理. 若是 PostMessage
的话, 一但将讯息丢出去, 就可以接着处理下个 tcx_GetEvent 了.
若 USB event 不是单纯的 ID, 而是透过一个 shared global 变数来传递,
那 SendMessage 本身可以想成一个是 synchonize 这个 global 变数的机制.
另一方面, 若 USB Event 的量很大, 使用 SendMessage 同步反而会限制住
worker thead 接受的速度, 那麽应该使用一个 receving queue, 收到的东
西往里面倒, 用 PostMessage 通知 UI 後, 就再紧接着收下个 USB Event
其他 WinAPI synchrnozation 的方式可以在 MSDN 上找找 Synchronization
Objects 有关的东西
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 114.43.5.247
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1508344424.A.1D3.html
1F:推 freaky: 简单说,只使用一个UI thread,其他thread用PostMessage() 10/28 23:24
2F:→ freaky: 避免使用SendMessage()以防止deadlock。 10/28 23:25