• <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>

            桃源谷

            心靈的旅行

            人生就是一場旅行,不在乎旅行的目的地,在乎的是沿途的風景和看風景的心情 !
            posts - 32, comments - 42, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

            準則5:盡可能避免線程的延遲撤銷處理

            Posted on 2008-12-25 14:08 lymons 閱讀(1330) 評論(0)  編輯 收藏 引用 所屬分類: C++CUnix/Linux文章翻譯
            From 2008精選

            [] UNIX上C++程序設計守則(5)Add star


            準則5: 盡可能避免線程中做延遲撤銷的處理

            • 線程的異步撤消是指:一個線程發出中斷其他線程的處理的一個動作
            • 延遲撤消因為是規格自由度比較高、所以根據OS和C庫函數的版本它也有各式各樣的動作
              • 要想在不同的環境下都能穩定的動作的話,就必須要詳細調查運行環境和,對C庫函數進行抽象化,做必要的條件編譯
              • 在C++中、「撤消發生時的對象釋放」的實現不具有可移植性
            • 線程撤銷要慎重使用。在C++里不要使用

            說明:


            在前面我們已經講過,線程的撤消分為「異步」「延遲」這兩種類型、并且「異步撤消」也是非常容易引起各種復雜問題的元兇。


            那么,現在要在程序中除掉「延遲撤消」。延遲撤消雖然不會像異步撤消那樣會引起各種各樣的問題、但是、注意事項還是有很多的。只有把下面的這些注意事項全部都把握之后才能放心使用。


            注意事項1: 要好好把握撤消點


            和異步撤消不一樣的是、撤消處理一直會被延遲到在代碼上明示出來的撤消點之后才會被執行。如果編寫了一個具有延遲撤消可能的代碼、代碼中的那條語句是撤消點、必須要正確的把握。


            首先、調用過pthread_testcancel函數的地方就變成撤消點了。當然這個函數是、僅僅為了「變成延遲撤消」的目的而設置出來的函數。除此之外、某些標準庫函數被調用后會不會變成撤消點是在規格(SUSv3)中決定的。請參照規格說明、有下面的函數一覽。


            下面的函數撤消點

            accept, aio_suspend, clock_nanosleep, close, connect, creat, fcntl, fdatasync,
            fsync, getmsg, getpmsg, lockf, mq_receive, mq_send, mq_timedreceive,
            mq_timedsend, msgrcv, msgsnd, msync, nanosleep, open, pause, poll, pread,
            pselect, pthread_cond_timedwait, pthread_cond_wait, pthread_join,
            pthread_testcancel, putmsg, putpmsg, pwrite, read, readv, recv, recvfrom,
            (略)
            下面的函數不是撤消點

            access, asctime, asctime_r, catclose, catgets, catopen, closedir, closelog,
            ctermid, ctime, ctime_r, dbm_close, dbm_delete, dbm_fetch, dbm_nextkey, dbm_open,
            dbm_store, dlclose, dlopen, endgrent, endhostent, endnetent, endprotoent,
            endpwent, endservent, endutxent, fclose, fcntl, fflush, fgetc, fgetpos, fgets,
            fgetwc, fgetws, fmtmsg, fopen, fpathconf, fprintf, fputc, fputs, fputwc, fputws,
            (略)

            看到這些我想已經明白了、但是在規格中也說明了「能否成為撤消點跟具體的實現相關的函數」也是多數存在的。原因是、為了可移植性、保證「在一定的時間內讓線程的延遲撤消完成」是很困難的事情*1。做的不好的話、只要稍微一提升OS的版本就可能讓做出來的程序產品不能動作。


            即使是這樣那還想要使用延遲撤消嗎?


            注意事項2: 實現要知道cleanup函數的必要性


            可能被延遲撤銷的線程在運行的過程中,要申請資源的場合,一定要考慮到以下的幾點,否則就會編制出含有資源丟失和死鎖的軟件產品。


            例如編寫的下面的函數就不能被安全的延遲撤銷掉。

            void* cancel_unsafe(void*) {
            static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
            pthread_mutex_lock(&mutex); // 此處不是撤消點
            struct timespec ts = {3, 0}; nanosleep(&ts, 0); // 經常是撤消點
            pthread_mutex_unlock(&mutex); // 此處不是撤消點
            return 0;
            }
            int main(void) {
            pthread_t t;
            // pthread_create后馬發上收到一個有效的延遲撤消的要求
            pthread_create(&t, 0, cancel_unsafe, 0);
            pthread_cancel(t);
            pthread_join(t, 0);
            cancel_unsafe(0); // 發生死鎖!
            return 0;
            }

            在上面的樣例代碼中、nanosleep執行的過程中經常會觸發延遲撤銷的最終動作,但是這個時候的mutex鎖還處于被鎖定的狀態。而且、線程一被延遲撤消的話就意味著沒有人去釋放掉這個互斥鎖了*2。因此、在下面的main函數中調用同樣的cancel_unsafe函數時就會引起死鎖了。


            為了回避這個問題、利用pthread_cleanup_push函數在撤消時釋放掉互斥鎖的話就OK了,也就不會死鎖了。

            // 新增清除函數
            void cleanup(void* mutex) {
            pthread_mutex_unlock((pthread_mutex_t*)mutex);
            }

            // 粗體字部分是新增的語句
            void* cancel_unsafe(void*) {
            static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
            pthread_cleanup_push(cleanup, &mutex);
            pthread_mutex_lock(&mutex);
            struct timespec ts = {3, 0}; nanosleep(&ts, 0);
            pthread_mutex_unlock(&mutex);
            pthread_cleanup_pop(0);
            return 0;
            }

            注意事項3: 實現要清楚延遲撤消和C++之間的兼容度


            使用C語言的場合,利用上面的pthread_cleanup_push/pop函數就能安全地執行延遲撤消的動作,但是在C++語言的場合就會出現其他的問題。C++與延遲撤消之間的兼容度是非常差的。具體的表現有以下兩個問題:


            1. 執行延遲撤消的時候,內存棧上的對象的析構函數會不會被調用跟具體的開發環境有關系
              • GCC3版本就不會調用。
              • Solaris和Tru64 UNIX下的原生編譯器的場合,就調用析構函數(好像)
            2. pthread_cleanup_push/pop函數和C++的異常處理機制之間有著怎樣的相互影響也能具體環境有關

            不調用析構函數,或者在拋出異常的時候不能做cleanup處理,經常是發生內存泄漏,資源丟失,程序崩潰,死鎖等現象的原因。令人意外的是對于這個深層次的問題,就連Boost C++庫都束手無策。

            [Q] Why isn't thread cancellation or termination provided?

            [A] There's a valid need for thread termination, so at some point Boost.Threads probably will include it, but only after we can find a truly safe (and portable) mechanism for this concept.

            先必須確保對象的自由存儲,而后全都讓cleanup函數去釋放對象的方法也有,但是這次是犧牲了異常安全性。
            (原文沒有看明白:オブジェクトを必ずフリーストア上に確保し、解體を全て、クリーンナップハンドラに行わせる手もありますが、今度は例外安全性が犠牲になるでしょう。)


            應該說的是,在使用C++的工程里不對線程進行延遲撤消處理還是比較實際的。

            *1:好的問題是 gethostbyname()函數

            *2:異步撤消跟malloc函數的例子很相似

            原文地址:http://d.hatena.ne.jp/yupo5656/20040725/p2

            我的個人簡歷第一頁 我的個人簡歷第二頁
            国产精品亚洲综合专区片高清久久久| 久久99精品久久久久久水蜜桃 | 久久精品中文无码资源站| 久久综合伊人77777| 性高朝久久久久久久久久| 一级A毛片免费观看久久精品| 久久国产亚洲精品| 97久久国产露脸精品国产| 久久99精品久久只有精品 | 亚洲欧美一级久久精品| 四虎国产精品成人免费久久| 亚洲av伊人久久综合密臀性色| 久久久久久a亚洲欧洲aⅴ| 久久亚洲av无码精品浪潮| 色综合久久综合中文综合网| 中文字幕成人精品久久不卡| 久久无码国产专区精品| 国产亚州精品女人久久久久久| 久久精品国产亚洲AV不卡| 品成人欧美大片久久国产欧美...| 久久精品国产亚洲AV不卡| 精品久久国产一区二区三区香蕉| 亚洲精品乱码久久久久66| 99久久精品费精品国产| 精品无码久久久久久午夜| 99久久国产宗和精品1上映| 欧洲国产伦久久久久久久| 91精品国产高清久久久久久国产嫩草| 久久久久久久久波多野高潮| 久久性精品| 国产日韩久久久精品影院首页| 色婷婷综合久久久中文字幕| 香蕉久久夜色精品国产2020| 国产一区二区精品久久岳| 999久久久国产精品| 久久久国产精品网站| 77777亚洲午夜久久多喷| 久久99国内精品自在现线| 久久久精品人妻一区二区三区蜜桃| 久久这里有精品| 久久精品卫校国产小美女|