※ 引述《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
|<