none
Thread裡使用UpdateAllViews() RRS feed

  • 問題

  • 各位大大好:

            小弟我寫了一個CDocument/View (SDI)的應用程式,在CDocument裡使用AfxBeginThread創造了一個Thread,並要在Thread裡不斷的更新Client區的影像,可是當我在Thread裡加入UpdateAllViews()並執行到這行時就會出現ASSERTION Failed的錯誤,在google上查了一下說是要用send message的方式處理,可是CDocument該怎麼送user defined message?或是有其他方式可以在Thread裡放UpdateAllViews()呢? 先感謝各位大大的回答摟~

    2012年4月26日 下午 05:20

解答

  • 各位大大好:

            小弟我寫了一個CDocument/View (SDI)的應用程式,在CDocument裡使用AfxBeginThread創造了一個Thread,並要在Thread裡不斷的更新Client區的影像,可是當我在Thread裡加入UpdateAllViews()並執行到這行時就會出現ASSERTION Failed的錯誤,在google上查了一下說是要用send message的方式處理,可是CDocument該怎麼送user defined message?或是有其他方式可以在Thread裡放UpdateAllViews()呢? 先感謝各位大大的回答摟~

    不可以用SendMessage而是PostMessage
    UpdateAllViews和SendMessage一樣都是直接呼叫Window Process處理訊息。
    在Widows的架構下,是不能跨Thread呼叫Window Process。
    取而代之,就是Post一個Uses Message,當目標Window Process收到User Message後
    再呼叫UpdateAlViews即可以。


    Sunyear

    2012年5月5日 上午 07:37

所有回覆

  • UpdateAllViews就是遍历各个view之后调用OnUpdate。你可以在OnUpdate那里发消息。


    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful, so they will appear differently to other users who are visiting your thread for the same problem.
    Visual C++ MVP

    2012年4月27日 上午 02:28
  • 可以呼叫CDocument類別的方法, 由方法改變CDocument類別管理的資料的內容, 再由CDocument本身呼叫UpdateAllViews, 不要由Thread代勞
    • 已編輯 tihsMVP 2012年4月27日 上午 03:05
    2012年4月27日 上午 03:05
  • 各位大大好:

            小弟我寫了一個CDocument/View (SDI)的應用程式,在CDocument裡使用AfxBeginThread創造了一個Thread,並要在Thread裡不斷的更新Client區的影像,可是當我在Thread裡加入UpdateAllViews()並執行到這行時就會出現ASSERTION Failed的錯誤,在google上查了一下說是要用send message的方式處理,可是CDocument該怎麼送user defined message?或是有其他方式可以在Thread裡放UpdateAllViews()呢? 先感謝各位大大的回答摟~

    不可以用SendMessage而是PostMessage
    UpdateAllViews和SendMessage一樣都是直接呼叫Window Process處理訊息。
    在Widows的架構下,是不能跨Thread呼叫Window Process。
    取而代之,就是Post一個Uses Message,當目標Window Process收到User Message後
    再呼叫UpdateAlViews即可以。


    Sunyear

    2012年5月5日 上午 07:37
  • 感謝各位大大的提醒,我使用了下面的方法解決了,在Thread裡呼叫CMyDoc::UpdateImage(),

    然後在CMyDoc::UpdateImage()裡呼叫CMyView::DoUpdateImage(),這樣就可以不斷更新

    Client Area,不過感覺繞了一圈,不知道這樣寫是否不好,有更有效率的寫法嗎?

    在CDocument裡加入一個member function :

         void CMyDoc::UpdateImage()

         {

                    CMyDoc* pView=CMyDoc::GetView();
                    pView->DoUpdateImage();

         }

    在CView裡加入一個member function :

         void CMyView::DoUpdateImage()

         {

                   Invalidate(NULL);
                   UpdateWindow();

         }

    2012年5月9日 下午 11:19
  • 感謝各位大大的提醒,我使用了下面的方法解決了,在Thread裡呼叫CMyDoc::UpdateImage(),

    然後在CMyDoc::UpdateImage()裡呼叫CMyView::DoUpdateImage(),這樣就可以不斷更新

    Client Area,不過感覺繞了一圈,不知道這樣寫是否不好,有更有效率的寫法嗎?

    在CDocument裡加入一個member function :

         void CMyDoc::UpdateImage()

         {

                    CMyDoc* pView=CMyDoc::GetView();
                    pView->DoUpdateImage();

         }

    在CView裡加入一個member function :

         void CMyView::DoUpdateImage()

         {

                   Invalidate(NULL);
                   UpdateWindow();

         }

    你還是沒吸收到精髓。
    在MFC裡一個Window所需存取使用的資料都繼承自CWnd。
    Window的訊息除了Modal Window有自己的收發訊息迴圈外,通常訊息由Main thread
    來做收發的迴圈(這個迴圈被MFC包起來了)。所以正常的Window在處理訊息函式(叫做WindowProc)
    是和Main thread在同一個執行緒。因為處理訊息時會存取CWnd(或其繼承類別)物件裡的成員。
    所以WindowProc不能跨執行緒呼叫(例如某個Thread正在改變某個資料時,
    被另一個thread中斷,改變一半的資料被也中斷的thread改變,最後回到被中斷的thread繼續未完成的
    的資料改變,這樣會有很大的問題,這在多緒編程叫"存取競速"議題,可以寫一本書)
    不管你怎麼輾轉呼叫,最後你呼叫UpdateWindow();時,還是在你原呼叫的Thread裡(不是Main Thread)。
    而UpdateWindow是用SendMessage(WM_PAINT,...)來呼叫WindowProc
    (避開了Message queue也遶過Main thread的訊息收發迴圈)
    正常的話,你的程式執行時系統應該會有錯襄警告,如果你騙過了系統,那不是僥倖而是不幸。
    (因為程式潛藏重大危機而不知)
    看到這裡,你了解是那裡不行了嗎?(若還不清楚,多看幾遍,真正了解了再往下看)

    要令不同執行緒的WindowProc處理特定的訊息,最簡單的就是PostMessage。
    PostMessage是把要執行的訊息置放到message queue,然後自然會由正確的訊息收發迴圈來處理。
    另外UpdateAllView是通知View Window資炓(document改改變,請更新);
    而UpdateWindow是告訴Window某個區域需要重畫。
    這是兩個截然不同意義的通知,雖然你可以把程式寫成只要重畫,資料就全部更新。
    但通常這樣做會有效率的問題,例如window只是一小塊被蓋住後又可見,這時只需要重畫那一小塊而已。
    資料更新,代表顯示的東西要重新來過。
    做任何事,都要清楚"為何而為",就算你有理由用重畫來替代資料更新。
    也要想到日後程式會很難閱讀。


    Sunyear



    2012年5月10日 上午 02:21
  • 感謝Sunyear Huang大大的指引,我應該再去仔細閱讀windows的信息機制,不過藉由你的說明給了我不小的進步。

    我了解全部重畫跟只重畫無效區在效率上是有差別的,只是想先把整體架構完成再來對細部去做修改,但還是謝謝你的意見

    2012年5月12日 下午 11:48