看板 C_and_CPP 關於我們 聯絡資訊
開發平台(Platform): (Ex: VC++, GCC, Linux, ...) VC2008 MFC 問題(Question): 請教物件在multi-thread的情況下,物件的生成、控管、以及刪除的時機 補充說明(Supplement): 不好意思,不才小弟又上來請教一下各位了。 我想跟版上的各位高手請教一下,在multi-thread下, 物件生成、控管、以及刪除的時機與原則。 小弟工作上接手的project是MFC。 以往我的觀念是,一個母物件底下有什麼子物件,就在母物件底下生成(new)。 要刪除子物件,就在母物件的解構裡面執行(delete)。 子物件裡面如果還有包新的物件,照以上原則處理。 但我接手的這個proj,以前同事開發的寫法不是這樣。 當MainFrame建立起來後,就一次把所有的dialog全部建立起來。 比方說這樣的架構 MainFrame - Sub-DialogA - Sub-DialogA1 \ Sub-DialogA2 \ Sub-DialogB - Sub-DialogB1 在MainFrame的OnCreate把5個dialog全部new起來, 然後分別把Dialog A1/A2的指標傳給DialogA的指標, DialogB1的指標傳給DialogB的指標。 刪除,當然全部在MainFrame的解構裡面做。 當然這樣也不是不可以,好處是把所有物件統一生成,統一刪除在同一處。 只是我不太喜歡,從屬關係要追一下程式碼。 追code不方便,除了統一生成統一刪除以外我不知還有什麼好處。 最近開始學習使用Multithread,碰上了一個問題。 我要寫一個自動下載的功能,架構如下 Create Create Create MainFrame -> DialogA -> _MonitorThread -> _DownloadThread (push queue) (pop queue) 1. MainFrame開啟timer自動push queue 2. DialogA在MainFrame底下生成 3. DialogA生成後開啟_MonitorThread 4. _MonitorThread監控queue,如果沒有東西下載(_DownloadThread指標為null),queue 裡面有東西,pop第一個執行_DownloadThread 5. 下載進度,_DownloadThread會顯示在DialogA中 5. 當_DownloadThread執行尚未結束前,_MonitorThread持續等待(WaitForSingleObject) 出現的問題是,如果user直接把UI整個關掉,MainFrame跑了OnDestroy, 在解構開始執行之前,我要等這兩個thread先結束,在abort flag丟給thread後, 我在MainFrame::OnDestroy裡面寫WaitForSingleObject(_MonitorThread) 測試結果發現常常會關不掉,檢查後發現我這樣的寫法會有dead lock。 問題出在於,_DownloadThread正好要把DialogA的顯示文字作更新的動作, DialogA在MainFrame底下生成,可是此時MainFrame執行WaitForSingleObject, 所以無法回應,形成死結。 找到原因後,我想我的DialogA不能在MainFrame裡面建立,要在thread裡面建立才行。 create create create create MainFrame -> _TestThread -> DialogA -> _MonitorThread -> _DownloadThread 在MainFrame裡面直接建一個新的_TestThread,只做一件事,把DialogA給建立起來。 //create thread //CWinThread* pTestThread; 寫在MainFrame的header裡面 pTestThrtead = AfxBeginThread(CreateDlgFun, this); //_TestThread UINT CMainThread::CreateDlgFun(LPVOID pParam) { CMainFrame* pMF = (CMainFrame*)pParam; CDialogA* pA = new CDialogA(); ... ... } //MainFrame OnDestroy void CMainFrame::OnDestroy() { ...... // WaitForSingleObject(_TestThread) } 我對於DialogA的建立,產生疑問: 1. CDialogA* pA = new CDialogA(); 如果pA為local變數,那我就必須要讓Thread的完成下載動作、或user取消之前, 不能結束,否則pA就消失了。 2. 如果pA被宣告在MainFrame的header裡面 // in CMainFrame header class CMainFrame { CDialog* pA; ... } //_TestThread UINT CMainThread::CreateDlgFun(LPVOID pParam) { CMainFrame* pMF = (CMainFrame*)pParam; if (pA != NULL) pA = new CDialogA(); ... ... } 改成這樣的寫法,pA儲存在物件中,生命週期跟物件相同,我要對pA做操作會比較容易。 但這樣一來,會不會產生原來的問題? 雖然DialogA在Thread裡面new出來,但是pA還是放在MainFrame物件中。 這樣當_DownloadThread要求DialogA變更顯示文字時,會不會dead lock? 我的想法是,Dialog是thread建的,應該是thread掌管,會不會回應是thread控制, pA只是記憶體的儲存位置,應該沒關係吧? 如果是的話,那麼pA new的時候需不需要Lock起來? 再來,刪除的時機為何? 1. 如果pA是local變數,那麼只要在thread結束前執行delete就好,沒問題。 2. 如果pA儲存在MainFrame物件呢? 我想應該還是要在thread結束前刪除吧?如果留給MainFrame去刪除, proj越來越大、thread越多,應該會產生一堆問題。 請教版上各位高手,在multithread的物件管理的原則? 觀念可能很基本,但我這菜鳥覺得如果寫multithread觀念沒建好,管理出問題, 恐怕會有解不完的bug。 另外還有個問題順便問一下。 我知道thread function要被宣告成static。 class裡面的任何東西一旦被宣告成static, class宣告的所有物件會共用被宣告為static的元件。 但我不解的是,那麼,thread的static function, 如果不放在物件裡面,變成global function,有什麼差別呢? 1. UINT static CMainFrame::_TestThread() 2. UINT static _TestThread() 請問有什麼差別? 還請版上各位高手指教,感激不盡! -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 114.43.211.61 ※ 文章網址: http://www.ptt.cc/bbs/C_and_CPP/M.1408650801.A.639.html
Killercat: 這優點就是pop dialog很快 因為早就生好了 08/22 12:45
Killercat: 缺點就是會略為拖到啟動時間 不過這個我認為不嚴重 08/22 12:46
TeaEEE: 要避免在thread中生成UI物件,因為MS不保証物件生成是thre 08/22 19:26
TeaEEE: Threadsafe 08/22 19:27
EdisonX: 在很多 setting dialog 很多的時候 , 這方法不就... orz 08/24 00:53
tyc5116: 同意3F,一個大原則,Thread只用來做數值運算,邏輯上的處理 08/26 09:22
tyc5116: UI的部份都避免掉 08/26 09:22
tyc5116: 你的"5. 下載進度",我會把更新的數值放某變數內 08/26 09:23
tyc5116: 然後Dialog開個Timer,作為更新介面上的資訊 08/26 09:24
tyc5116: 如此,Thread可以完全避免掉UI的部份 08/26 09:25