項目簡介和code見《同步非同步和阻塞2-測試小項目》 1. 實現 由於IO是阻塞的,所以要實現輪詢IO的結果,需要將IO放入線程中處理,IO的處理結果作為給線程的exit code返回。這裡用“CBaseThread”簡單的將線程處理函數封裝到類中 在OnStart()中,先依次啟動2個線程處理IO ...
項目簡介和code見《同步非同步和阻塞2-測試小項目》
1. 實現
由於IO是阻塞的,所以要實現輪詢IO的結果,需要將IO放入線程中處理,IO的處理結果作為給線程的exit code返回。這裡用“CBaseThread”簡單的將線程處理函數封裝到類中
unsigned CSyncIOByPolling::ThreadWork() { return IO(); }
在OnStart()中,先依次啟動2個線程處理IO,然後輪詢,一旦有任何一個IO的線程處理完畢後就發送結果
為了不把CPU占滿,這裡每次輪詢設了一個sleep的時間間隔,然後通過NotifyProgress()函數通知UI當前的進度。
bool CSyncIOByPolling::OnStart() { int nRetArray[] = {-1, -1}; HANDLE hThreadArray[] = {NULL, NULL}; int nThreadNum = sizeof(hThreadArray) / sizeof(hThreadArray[0]); for (int i = 0; i < nThreadNum; i++) { hThreadArray[i] = StartThread(); } int nIndex = 0; int nCompletedNum = 0; //polling get IO result while (true) { for (int i = 0; i < nThreadNum; i++) { if (hThreadArray[i]) { NotifyProgress(nIndex, i); DWORD dwExitCode = STILL_ACTIVE; if(::GetExitCodeThread(hThreadArray[i], &dwExitCode)) { if (STILL_ACTIVE != dwExitCode) { nRetArray[i] = dwExitCode; } else { continue; } } ::CloseHandle(hThreadArray[i]); hThreadArray[i] = NULL; NotifyResult(nRetArray[i], i); nCompletedNum++; } } if (nCompletedNum >= nThreadNum) { break; } Sleep(TIMER_ELAPSE); nIndex += TIMER_ELAPSE; } return true; }
簡單的從代碼長度來看,同步非阻塞模式就明顯比同步阻塞模式要複雜。
2. 測試
和同步阻塞模式一樣,在OnStart()未返回前,”Stop”按鈕一直是不可用的,同時UI界面也被卡住(同步模式的老毛病)。
1> 在同步非阻塞模式下,雖然IO Result還沒有結果,卻可以看到不斷前進的”Progress”(這裡由於不知道IO什麼時候結束,實際是當前的用掉的時間),這樣用戶能夠知道雖然UI卡住了,但起碼程式還是沒掛掉的,這就是不阻塞下能多乾一些其他有意義的事情帶來的好處。
2> 如果IO沒有提供timeout的設置(如本例中的IO()),也可以在輪詢中設置一個最大的輪詢時間,防止OnStart()一直不返回,導致主線程(很多時候都是UI)不能正常運行。
3> 輪詢模式中使用了多線程,這樣實際實現了IO併發,在多個IO處理中,可以縮短所有IO任務處理的總時間
所以從用戶體驗上來看,同步非阻塞模式是要優於同步阻塞模式的。
當然,這裡存在一個輪詢間隔的問題,一直輪詢或輪詢間隔小,CPU會大量消耗在無太多意義的輪詢code上,如果輪詢間隔設得過大,如1s,但如果IO實際完成的時間只有10ms,那麼實際IO的完成時間會延長到1s,這反而不如同步阻塞模式了。