青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

桃源谷

心靈的旅行

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

UNIXC++程序設計守則 (2)
原文地址:http://d.hatena.ne.jp/yupo5656/20040712/p2

準則2: 要知道信號處理函數中可以做那些處理
· 在用sigaction函數登記的信號處理函數中可以做的處理是被嚴格限定的
· 僅僅允許做下面的三種處理
   1. 局部變量的相關處理
   2. “volatile sig_atomic_t”類型的全局變量的相關操作
   3. 調用異步信號安全的相關函數
· 以外的其他處理不要做

 
說明
因為在收到信號時要做一些處理,那通常是準備一個信號處理函數并用sigaction函數把它和信號名進行關聯的話就OK了。但是,在這個信號處理函數里可以做的處理是像上面那樣被嚴格限定的。沒有很好掌握這些知識就隨便寫一些代碼的話就會引起下面那樣的問題
· 問題1: 有程序死鎖的危險
   o  這是那些依賴于某一時刻,而且錯誤再現比較困難的BUG產生的真正原因
   o  死鎖是一個比較典型的例子,除此之外還能引起函數返回值不正確,以及在某一函數內執行時突然收到SEGV信號等的誤操作。
   譯者注1SEGV通常生在試圖訪問無效內存區域(可能是個NULL,或超出程空之外的內存地址)。當bug原因和SEGV影響在不同時間現時,它別難于捕到。


· 問題2: 由于編譯器無意識的優化操作,有導致程序紊亂的危險
   o  這是跟編譯器以及編譯器優化級別有關系的bug。它也是“編譯器做了優化處理而不能正常動作”,“因為inline化了程序不能動作了”,“變換了OS了程序也不能動作”等這些解析困難bug產生的原因。

 
還是一邊看具體的代碼一邊解說吧。在下面的代碼里至少有三個問題,根據環境的不同很可能引起不正確的動作*1按照次序來說明里面的錯誤

 

 1int gSignaled;
 2void sig_handler(int signo) {
 3    std::printf("signal %d received!\n", signo);
 4    gSignaled = 1;
 5}

 6int main(void{
 7    struct sigaction sa;
 8  // (省略)
 9  sigaction(SIGINT, &sa, 0);
10    gSignaled = 0;
11    while(!gSignaled) {
12  //std::printf("waiting\n");
13        struct timespec t = 10 }; nanosleep(&t, 0);
14    }

15}

16

 

錯誤1: 競爭條件
    在上面的代碼里有競爭條件sigaction函數被調用后gSignaled還未被賦值成0值之前,如果接受到SIGINT信號了那會變得怎么樣呢? 在信號處理函數中被覆寫成1后的gSignaled會在信號處理函數返回后被初始化成0在后面的while循環里可能會變成死循環


錯誤2: 全局變量gSignaled 聲明的類型不正確
     在信號處理函數里使用的全局變數gSignaled的類型沒有聲明成volatile sig_atomic_t 這樣的話在執行while循環里的代碼的時候接收到了了SIGINT信號時有可能引起while的死循環那為什么能引起這樣的情況呢
    · 信號處理函數里,把內存上gSignaled的值變更成1 ,它的匯編代碼如下:

 

          movl    $1, gSignaled

    · 但是,就像下面的代碼描述的那樣,main函數是把gSignaled的值存放到了寄存器里while循環之前,僅僅是做了一次拷貝變量gSignaled內存上的值到寄存器里而在while循環里只是參照這個寄存器里的值
          movl     gSignaled, %ebx
       .L8:
                       testl    %ebx, %ebx
                       jne      .L8

     在不執行優化的情況下編譯后編譯器有可能不會生成上面那樣的偽代碼Gcc當使用-O2選項做優化編譯時,生成的實際那樣的匯編代碼產生的危害并不僅僅是像上面說的威脅那樣簡單。這方面的問題,是設備驅動的開發者所要知道的常識,但現實情況是對于應用程序的設計者.開發者幾乎都不知道這些知識。
為了解決上面的問題,全局變量gSignaled的類型要像下面那樣聲明

     volatile sig_atomic_t gSignaled;

     volatile則是提示編譯器不要像上面那樣做優化處理,變成每次循環都要參照該變量內存里的值那樣進行編譯。所以在信號處理函數里把該變量的值修改后也能真實反映到main函數的while循環里
sig_atomic_t 是根據CPU類型使用typedef來適當定義的整數值,例如x86平臺是int就是指用一條機器指令來更新內存里的最大數據*2在信號處理函數里要被引用的變量必須要定義成sig_atomic_t類型那么不是sig_atomic_t類型的變量(比如x86平臺上的64位整數)就得使用兩條機器指令來完成更新動作。如果在執行一條機器指令的時候突然收到一個信號而程序執行被中斷,而且在信號處理函數中一引用這個變量的話,就只能看到這個變量的部分的值。另外,由于字節對齊的問題不能由一條機器指令來完成的情況也會存在。把該變量的類型變成sig_atomic_t的話,這個變量被更新時就只需要一條機器指令就可以完成了。所以在信號處理函數里即使使用了該變量也不會出現任何問題

     2006/1/16 補充: 有一點東西忘記寫了關于sig_atomic_t詳細的東西,請參考C99規范的§7.14.1.1/5小節在信號處理函數里對volatile sig_atomic_t以外的變量進行修改,其結果都是"unspecified"(參照譯者注2)另外, sig_atomic_t類型的變量的取值范圍是在SIG_ATOMIC_MIN/MAX之間 (參見§7.18.3/2)有無符號是跟具體的實現有關。考慮到移植性取值在0127之間是比較合適的C99也支持這個取值范圍C++規范(14882:2003)里也有同樣的描述確切的位置是§1.9/9這里SUSv3的相關描述請參考sigaction這里*3此外雖然在GCC的參考手冊里也說了把指針類型更新成原子操作,但在標準C/C++卻沒有記載*4
譯者注2
           When the processing of the abstract machine is interrupted by receipt of a signal, the value of objects with type other than volatile sig_atomic_t are unspecified, and the value of any object not of volatile sig_atomic_t that is modified by the handler becomes undefined.
                       ------
ISO/IEC FDIS 14882:1998(E) 1.9小節


錯誤3: 在信號處理函數里調用了不可重入的函數
上述的樣例代碼中調用了printf函數,但是這個函數是一個不可重入函數,所以在信號處理函數里調用的話可能會引起問題。具體的是,在信號處理函數里調用printf函數的瞬間,引起程序死鎖的可能性還是有的。但是,這個問題跟具體的時機有關系,所以再現起來很困難,也就成了一個很難解決的bug了。
下面講一下bug發生的過程。首先講解一下printf函數的內部實現。
    · printf函數內部調用malloc函數
    · malloc函數會在內部維護一個靜態區域來保存mutex是為了在多線程調用malloc函數的時候起到互斥的作用
    · 總之malloc函數里有“mutex鎖定,分配內存,mutex解鎖”這樣“連續的不能被中斷”的處理

 

main関數:
  call printf  // while循環中的printf函數
    call malloc
      call pthread_mutex_lock(鎖定malloc函數內的靜態
mutex)
      // malloc處理時
..
收到SIGINT信號

        call sig_handler
          call printf // 信號處理函數中的printf函數

            call malloc
              call pthread_mutex_lock(鎖定malloc函數內的靜態
mutex)
              // 相同的mutex一被再度鎖定,就死鎖啦!!

 
     知道上面的流程的話像這樣的由于信號中斷引起的死鎖就能被理解了吧。為了修正這個bug,在信號處理函數里就必須調用可重入函數。可重入函數的一覽表在UNIX規范 (SUSv3)有詳細記載*5你一定會驚訝于這個表里的函數少吧。
另外,一定不要忘記以下的幾點:
    · 雖然在SUSv3里有異步信號安全(async-signal-safe)函數的一覽,但根據不同的操作系統,某些函數是沒有被實現的。所以一定要參考操作系統的手冊
    · 第三者做成的函數,如果沒有特別說明的場合,首先要假定這個函數是不可重入函數,不能隨便在信  號處理函數中使用。
    · 調用不可重入函數的那些函數就會變成不可重入函數了


    最后,為了明確起見,想說明一下什么是異步信號安全(async-signal-safe)”函數異步信號安全函數是指在該函數內部即使因為信號而正在被中斷,在其他的地方該函數再被調用了也沒有任何問題。如果函數中存在更新靜態區域里的數據的情況(例如,malloc),一般情況下都是不全的異步信號函數。但是,即使使用靜態數據,如果在這里這個數據時候把信號屏蔽了的話,它就會變成異步信號安全函數了。
譯者注3:不可重入函數就不是異步信號安全函數

 


*1sigaction函數被調用前,一接收到SIGINT信號就終止程序,暫且除外吧
*2“最大”是不完全正確的例如,Alpha平臺上32/64bit的變量用一條命令也能被更新,但是好像把8/16bit的數據更新編程了多條命令了http://lists.sourceforge.jp/mailman/archives/anthy-dev/2005-September/002336.html 請參考這個URL地址
*3If the signal occurs other than as the result of calling abort(), kill(), or raise(), the behavior is undefined if the signal handler calls any function in the standard library other than one of the functions listed in the table above or refers to any object with static storage duration other than by assigning a value to a static storage duration variable of type volatile sig_atomic_t. Furthermore, if such a call fails, the value of errno is unspecified.
*4在這個手冊里“ In practice, you can assume that int and other integer types no longer than int are atomic. ”這部分是不正確的請參照Alpha的例子
*5The following table defines a set of functions that shall be either reentrant or non-interruptible by signals and shall be async-signal-safe. 后面有異步信號安全函數一覽

我的個人簡歷第一頁 我的個人簡歷第二頁
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            免费亚洲婷婷| 蜜臀av在线播放一区二区三区| 韩国精品一区二区三区| 日韩视频在线免费观看| 好吊成人免视频| 午夜精品理论片| 亚洲专区欧美专区| 欧美精品在线播放| 亚洲东热激情| 曰韩精品一区二区| 午夜精品视频| 欧美一区二区视频在线观看| 欧美日韩在线播放一区| 亚洲电影在线| 亚洲精品欧美精品| 欧美成人乱码一区二区三区| 麻豆国产精品va在线观看不卡| 国产精品综合久久久| 亚洲午夜三级在线| 亚洲欧美激情视频| 国产精品夫妻自拍| 亚洲免费一级电影| 欧美一区二区三区在线免费观看| 国产精品成人观看视频国产奇米| 99国内精品| 亚洲淫片在线视频| 国产精品青草久久| 香蕉成人伊视频在线观看| 欧美在线观看视频一区二区三区| 国产精品久久久久久五月尺| 亚洲午夜一区二区三区| 西西裸体人体做爰大胆久久久| 国产精品大片wwwwww| 亚洲永久免费观看| 久久久久久亚洲综合影院红桃 | 欧美成人一区二区三区| 亚洲第一黄网| 欧美本精品男人aⅴ天堂| 亚洲黄一区二区| 一区二区三区日韩精品| 国产精品久久91| 欧美亚洲尤物久久| 蜜臀va亚洲va欧美va天堂| 在线播放中文一区| 欧美日韩成人一区| 亚洲永久字幕| 欧美成ee人免费视频| 亚洲精品一区二区三区四区高清 | 卡通动漫国产精品| 亚洲国产日韩欧美在线99| 一本色道久久88精品综合| 欧美四级剧情无删版影片| 亚洲欧美日韩第一区| 麻豆精品视频| 9色porny自拍视频一区二区| 国产精品一区=区| 美腿丝袜亚洲色图| 久久精品卡一| 国产精品日韩在线| 亚洲精品在线看| 欧美一区成人| 麻豆精品精品国产自在97香蕉| 亚洲国产成人av在线| 欧美日韩国内| 久久av老司机精品网站导航| 亚洲国产另类久久精品| 羞羞答答国产精品www一本| 亚洲国产裸拍裸体视频在线观看乱了| 欧美久久99| 欧美一区二区在线视频| 亚洲精品久久久蜜桃| 久久久久国产精品www| 亚洲神马久久| 亚洲国产精品一区二区第四页av| 国产精品xvideos88| 欧美aaa级| 久久精品99久久香蕉国产色戒| 亚洲精品国产精品国自产观看浪潮| 欧美一区二区三区在线播放| 亚洲肉体裸体xxxx137| 国产精品国色综合久久| 欧美黄色影院| 久久久精品网| 午夜精品久久久久久久白皮肤 | 亚洲视频在线观看网站| 欧美a一区二区| 久久久久88色偷偷免费| 亚洲欧美一区二区原创| 亚洲精品国产视频| 亚洲电影免费观看高清完整版在线观看| 国产精品高潮呻吟久久| 欧美激情综合网| 蜜桃久久av一区| 久久九九全国免费精品观看| 性欧美8khd高清极品| 亚洲网站啪啪| 中文在线资源观看视频网站免费不卡| 亚洲国产日韩综合一区| 你懂的视频欧美| 免费视频亚洲| 欧美mv日韩mv国产网站| 卡通动漫国产精品| 久久天天综合| 久久久精品国产99久久精品芒果| 午夜亚洲福利| 亚洲欧美视频| 欧美一区亚洲二区| 欧美一级黄色录像| 欧美伊人精品成人久久综合97| 亚洲婷婷在线| 欧美一区二区在线视频| 欧美一级专区免费大片| 欧美在线国产精品| 久久久精品免费视频| 久久久久国产免费免费| 久久久亚洲一区| 欧美暴力喷水在线| 欧美激情视频网站| 亚洲人体一区| 亚洲神马久久| 欧美一区二区免费| 久久亚洲一区二区| 欧美成人官网二区| 欧美色图五月天| 国产精品中文在线| 国内揄拍国内精品久久| 91久久极品少妇xxxxⅹ软件| 一区二区三区|亚洲午夜| 亚洲欧美综合v| 久久久久高清| 亚洲国产精品高清久久久| 日韩视频专区| 欧美在线亚洲一区| 欧美电影打屁股sp| 国产精品久久久| …久久精品99久久香蕉国产| 亚洲精品视频在线观看网站| 亚洲男女自偷自拍| 久久午夜精品| 亚洲乱码国产乱码精品精可以看| 亚洲女女女同性video| 久久久亚洲一区| 欧美视频中文在线看| 激情另类综合| 亚洲图片在线| 麻豆精品在线播放| 亚洲图片在线观看| 蜜臀99久久精品久久久久久软件| 欧美日韩国产片| 极品尤物av久久免费看| 亚洲一区成人| 欧美成人一区二免费视频软件| 一个人看的www久久| 久久久青草青青国产亚洲免观| 欧美色综合网| 亚洲国产精品成人va在线观看| 亚洲一区二区三区免费观看| 欧美成人精品在线观看| 亚洲一区二区三区久久| 欧美v日韩v国产v| 国内外成人免费激情在线视频| 亚洲麻豆国产自偷在线| 美日韩免费视频| 亚洲一区二区少妇| 欧美精品一区二区三区很污很色的| 国产日本精品| 亚洲欧美日韩精品久久久久| 亚洲成人在线网| 久久精品99久久香蕉国产色戒| 欧美亚洲成人网| 日韩手机在线导航| 欧美粗暴jizz性欧美20| 亚洲欧洲av一区二区| 欧美性大战久久久久久久蜜臀| 亚洲国内精品| 免费亚洲电影| 久久久精品国产免大香伊| 国产精品免费一区豆花| 亚洲最新在线| 亚洲欧洲日本一区二区三区| 久久久久免费观看| 国语自产在线不卡| 久久国产综合精品| 亚洲在线观看| 国产精品视频精品| 亚洲欧美在线免费观看| 一区二区不卡在线视频 午夜欧美不卡在 | 一区二区毛片| 亚洲欧洲日韩在线| 欧美高清在线观看| 亚洲精品视频在线播放| 亚洲精品1区2区| 欧美精品一区二区三区一线天视频| 亚洲国产综合视频在线观看| 欧美国产欧美亚洲国产日韩mv天天看完整 | 一本色道久久综合亚洲精品高清| 欧美精品久久99| 一区二区三区视频观看| 日韩视频在线一区| 欧美亚男人的天堂|