• <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久久这里只有精品| 久久亚洲国产精品成人AV秋霞| 久久久久久夜精品精品免费啦| 韩国三级大全久久网站| 久久久久人妻精品一区三寸蜜桃| 中文字幕精品久久久久人妻| 99久久无码一区人妻a黑| 久久精品国产72国产精福利| 亚洲色大成网站WWW久久九九| 99久久夜色精品国产网站| 久久99久久99精品免视看动漫 | 性做久久久久久免费观看| 国产69精品久久久久9999APGF | 久久亚洲国产精品一区二区| 亚洲精品第一综合99久久| 嫩草伊人久久精品少妇AV| 开心久久婷婷综合中文字幕| 国产精品久久久天天影视| 久久综合亚洲色一区二区三区| 国产A级毛片久久久精品毛片| 日韩欧美亚洲综合久久| 青青草原综合久久大伊人导航| 91亚洲国产成人久久精品| 久久精品国产亚洲AV香蕉| 久久久精品久久久久影院| 久久精品国产亚洲一区二区三区| 久久久91精品国产一区二区三区| 亚洲AV无码一区东京热久久| 精产国品久久一二三产区区别| 少妇久久久久久被弄到高潮 | 久久香蕉国产线看观看精品yw| 久久久久香蕉视频| 久久久综合香蕉尹人综合网| 国产精品日韩欧美久久综合| 国内精品免费久久影院| 国产L精品国产亚洲区久久| 狠狠人妻久久久久久综合蜜桃| 久久久黄片| 中文成人久久久久影院免费观看| 精品国产日韩久久亚洲| 亚洲精品蜜桃久久久久久|