• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            woaidongmao

            文章均收錄自他人博客,但不喜標題前加-[轉貼],因其丑陋,見諒!~
            隨筆 - 1469, 文章 - 0, 評論 - 661, 引用 - 0
            數(shù)據(jù)加載中……

            C++對象是怎么死的

              我承認這個帖子的名稱有標題黨的嫌疑,但是暫時想不出更好的名稱了,只好先這樣了 :-(
              由于前天的帖子聊了架構設計的多進程問題,所以今天想起來要聊一下和“C++進程終止相關的那些事。與前幾個C++帖子的風格類似,今天聊的內容,盡量局限于標準C++范疇,盡量不涉及特定的操作系統(tǒng)平臺。
            進程篇
              關于進程的三種死法
              由于今天講的是進程篇,自然得先搞明白進程的幾種死法。其實進程和大活人一樣,也有三種死法,分別是自然死亡、自殺、它殺。這三種死亡方式具體如下:
              1、自然死亡
              望文生義,自然死亡就是最自然的進程退出方法。具體表現(xiàn)為通過return語句結束main函數(shù)。由于這種方法最優(yōu)雅(后面會說),如果沒有其它特殊原因,強烈建議采用這種死法。
              2、自殺
              所謂的自殺,就是進程自己調用某些API來自行了斷。在標準C++中,這幾個函數(shù)(exitabortterminateunexpected)可以用于進程自殺。如果沒有額外設置,unexpected函數(shù)默認會調用terminate函數(shù),terminate函數(shù)默認會調用abort函數(shù)。所以自殺的方式基本上也就是exitabort兩種。exit相對abort來說溫和一些,所以下文稱exit溫和自殺;相對地,把abort稱為激進自殺
              3、它殺
              它殺其實也挺好理解,就是當前進程被其它進程殺死。標準C++沒有提供用于它殺的API函數(shù),因此常用的方法是通過某些跨平臺的庫(如ACE)提供的API函數(shù)或者調用某些外部命令(如Posix系統(tǒng)的kill命令)來實現(xiàn)。
              上面說了這幾種死法,有同學要問了:進程不同的死法和C++對象有什么關系捏?其實關系大大滴,請聽我細細道來。

              
            類對象的析構(銷毀)
              首先把類對象分為三種:局部非靜態(tài)對象、局部靜態(tài)對象、非局部對象(出于習慣,以下簡稱全局對象)。對于尚不清楚這幾種對象差異的同學,請先找本C++入門書拜讀一下。進程不同的死法對于這幾種對象是否能銷毀會有很大的影響。請看如下的對照表:
            ------------------------------
                    局部非靜態(tài)對象  局部靜態(tài)對象  全局對象
              自然死亡    能        能      能
              溫和自殺    不能       能      能
              激進自殺    不能       不能     不能
               它殺     不能       不能     不能
            ------------------------------
              從這個對照表可以看出,激進自殺和它殺的效果類似(各種類對象都無法正常銷毀)。所以我們在寫程序時要極力避免上述這兩種情況。
              另外,溫和自殺也有不爽之處:不能正確地銷毀局部非靜態(tài)對象。準確地說,應該是:在調用exit之前已經構造但是尚未析構的局部非靜態(tài)對象將再也不會被析構。所以溫和自殺也要避免使用。
              綜上所述,最正經、最靠譜的死法就是第一種:自然死亡。

              
            析構的順序
              那么,是不是只要讓進程自然死亡就萬事大吉了?非也!即使所有的類對象都會被析構,還有另一個棘手的問題:析構的順序。先來看下面一個例子:


            class CFoo
            {
            public:
              CFoo()
              {
                cout << "CFoo" << endl;
              }
              virtual ~CFoo()
              {
                cout << "~CFoo" << endl;
              }
            };


              上述示例挺簡單的(有效代碼僅6行),大伙兒能看出有什么問題嗎?如果你一眼就看出問題之所在,恭喜你,后面的內容你不用看了。
              對于用戶定義的全局對象,在C++標準中并沒有規(guī)定它們構造和析構的先后順序;對于諸如標準輸入輸出流的coutcerr等全局對象,在C++ 03標準中(參見27.4.2.1.6章節(jié))有提及如何保證它們在最后析構。但由于某些老式編譯器并未完全遵照標準實現(xiàn),導致標準輸入輸出流的幾個全局對象也可能被提前析構。
              基于上述原因,假如CFoo類也定義了一個全局對象g_foo。當g_foo析構的時候,cout對象可能已經先死了(取決于具體的環(huán)境,詳見關于標準輸入輸出流的進一步探討)。在這種情況下,CFoo析構函數(shù)的打印語句由于引用了已死的對象,可能會導致不可預料的后果。
              從上面的例子可以看出,如果你在程序中使用了全局對象或者靜態(tài)對象,那你要非常小心地編寫相關class/struct的析構函數(shù)代碼,盡量不要在它們的析構函數(shù)中引用其它的全局對象或靜態(tài)對象。當然啦,假如能避免使用全局對象和靜態(tài)對象,就更好了。
              另外,在C++經典名著《Modern C++ Design》的第6章詳細描述了關于單鍵(Singleton)銷毀的一些細節(jié)、場景及解決方法。大伙兒可以去拜讀一下。
              下一個帖子,會聊一下和線程有關的C++對象是怎么死的


            追求原創(chuàng),歡迎轉載。
            轉載必須包含本聲明、保持本文完整。并以超鏈形式注明作者編程隨想和本文原始地址:
            http://program-think.blogspot.com/2009/02/cxx-object-destroy-with-process.html

             

            Win32線程篇

              在前面的帖子里聊完了進程終止對C++對象析構的影響。今天咱們來說一下線程對于C++對象析構的影響。
              由于C++ 03標準沒有包含線程的概念,而C++ 0x尚未正式發(fā)布。所以對線程的討論只好根據(jù)特定的操作系統(tǒng)平臺來談。對于操作系統(tǒng)自帶的線程API,目前比較流行的款式是Windows平臺提供的線程APIPOSIX平臺上的pthread API。但是這兩種線程API的差異實在是太大,沒法拿出來一起聊。我只好把線程篇的帖子再拆分一下,今天先來聊一聊Win32的線程API
              另外,對于進行跨平臺開發(fā)的同學,應該已經用上了某些跨平臺的第三方線程庫(比如ACEBoost等),對于這些庫的介紹,初步打算放到C++的可移植性和跨平臺開發(fā)系列中。

              
            兩套APIOS API vs CRT API
              本來照例要先介紹線程的幾種死法,但是考慮到很多Windows程序員經常混淆線程API,搞不清楚到底該用哪個。所以先來說一下兩套線程API的問題。
              首先,Windows操作系統(tǒng)本身提供了線程的創(chuàng)建函數(shù)CreateThread和銷毀函數(shù)ExitThread。其中的CreateThread用于創(chuàng)建線程,ExitThread用于在線程函數(shù)內部推出線程(也就是自殺)。
              其次,在Visual C++自帶的C運行庫(以下簡稱CRT)中,還帶了另外4API函數(shù),分別是:_beginthread_endthread_beginthreadex_endthreadex。其中的_beginthread_beginthreadex用于創(chuàng)建線程(它們內部調用了CreateThread),_endthread_endthreadex用于自殺(它們內部調用了ExitThread)。
              有同學看到這里,被搞懵了,心想:干嘛要搞這么多玩意兒出來糊弄人?有CreateThreadExitThread不就夠了嘛!其實你有所不知,此中大有奧妙啊。
              因為OS API作為操作系統(tǒng)本身提供的API函數(shù),它被設計為語言無關的。它們不光可以被C++調用,還可以被其它諸如VBPythonDelphi等開發(fā)語言來調用。所以它們不會(也不能夠)幫你處理一些和具體編程語言相關的瑣事。
              而CRT API雖然最終還是要調用OS API來完成核心的功能,但是CRT API在不知不覺中多幫我們干了一些雖瑣碎但重要的工作。(如果同學們想窺探一下CRT API內部都干了些啥,可以拜讀一下Win32編程的經典名著《Windows 核心編程》的6.7章節(jié),里面介紹得挺細致的)
              費了這么多口水,無非是要同學們牢記:以后在Windows平臺下開發(fā)多線程程序,千萬不要直接使用這兩個線程API(也就是CreateThreadExitThread),否則后果自負 :-)
              另外,順便補充一下。除了上述提到的CRT庫。其它一些Windows平臺的C++庫也可能提供了線程的啟動函數(shù)(比如MFCAfxBeginThread),這些函數(shù)也對OS API進行了包裝,所以用起來也是安全的。

              
            三種死法
              說完了兩套API,開始來討論一下線程的幾種死法。線程和進程一樣,也有三種死法。詳見如下:
              1、自然死亡
              一般來說,每個線程都會對應某個函數(shù)(以下稱為線程函數(shù))。線程函數(shù)是線程運行的主體。所謂的自然死亡,就是通過return語句結束線程函數(shù)的執(zhí)行。
              2、自殺
              所謂的自殺,就是當前線程通過調用某API自己給停掉。前面已經說了OS API的壞話,同學們應該明白不能再用它們。那我們能否使用CRT API來進行自殺呢?請看msdn上的相關文檔:http://msdn.microsoft.com/en-us/library/hw264s73.aspx。上面說了,如果使用_endthread_endthreadex,將導致析構函數(shù)不被調用。
              3、它殺
              所謂的它殺,很明顯,就是其它線程通過調用某API把當前線程給強行停掉。對于Windows平臺來說,實現(xiàn)它殺比較簡單,使用TernimateThread就直接干掉了(它殺也是最野蠻的)。

              
            類對象的析構
              照前一個帖子的風格,還是把類對象分為三種:局部非靜態(tài)對象、局部靜態(tài)對象、非局部對象。由于非局部對象是在main之前就創(chuàng)建、在進程死亡時析構,暫時與線程扯不上太大關系。剩下的兩種局部對象,在宿主線程(所謂宿主線程,就是創(chuàng)建該局部對象的線程)死亡時會受到什么影響捏?請看如下的對照表:
            -------------------------
                   局部非靜態(tài)對象  局部靜態(tài)對象
             自然死亡    能        能
              自殺     不能       能
              它殺     不能       能
            -------------------------
              從上述結果可以看出,Windows上線程的死法還是以自然死亡為最安全,這點和進程的死法類似。所以同學們在Windows上開發(fā)時,要盡量避免自殺和它殺。

              
            關于主線程之死
              所謂主線程,就是進程啟動時,操作系統(tǒng)為該進程默認創(chuàng)建的第一個線程。通俗地講,可以把main函數(shù)看成是主線程的線程函數(shù)。
              主線程之死是有講究的。由于前面已經闡述了非自然死亡的壞處,所以我們只討論主線程自然死亡這一種情況。當主線程自然死亡時(也就是用returnmain返回時),會導致exit函數(shù)被調用,exit函數(shù)就會開始清除當前進程的各種資源,為進程的死亡作準備。這時候,如果還有其它活著的線程,也會被一起干掉(其效果類似于它殺)。
              為了防止出現(xiàn)上述情況,主線程一定要負責最終的善后工作。務必等到其它線程都死了,它才能死。

              Windows平臺上,有關線程的對象析構問題,就聊到這。下一個帖子,咱們來聊一下pthread相關的對象析構話題。


            轉載必須包含本聲明、保持本文完整。并以超鏈接形式注明作者編程隨想和本文原始地址:
            http://program-think.blogspot.com/2009/03/cxx-object-destroy-with-thread-win32.html

             

            posted on 2009-03-06 23:27 肥仔 閱讀(626) 評論(0)  編輯 收藏 引用 所屬分類: C++ 基礎

            精品久久久无码21p发布| 久久午夜福利电影| 久久99精品久久久久子伦| 久久综合给久久狠狠97色| www性久久久com| 久久er国产精品免费观看8| 久久综合亚洲色HEZYO社区| 无码人妻久久一区二区三区免费| 成人资源影音先锋久久资源网| 国产成人久久久精品二区三区| 久久久久久亚洲精品影院| 国产午夜免费高清久久影院| 久久综合九色综合久99| 无码日韩人妻精品久久蜜桃| 国产午夜电影久久| 久久久久久夜精品精品免费啦| 久久青青草原亚洲av无码| 国产成人精品白浆久久69| 久久大香萑太香蕉av| 久久黄视频| 欧美一区二区精品久久| 77777亚洲午夜久久多喷| 无码乱码观看精品久久| 青草影院天堂男人久久| 久久国产热精品波多野结衣AV| 欧美日韩精品久久久免费观看| 一本大道久久a久久精品综合| 无码国产69精品久久久久网站| 欧洲性大片xxxxx久久久| 国产精品热久久毛片| 成人久久精品一区二区三区| 久久久一本精品99久久精品88 | 久久偷看各类wc女厕嘘嘘| 国产免费久久精品99re丫y| 日韩电影久久久被窝网| 久久久久一本毛久久久| 久久久久成人精品无码| 色播久久人人爽人人爽人人片aV| 久久久久成人精品无码| 亚洲国产高清精品线久久| 香蕉久久久久久狠狠色|