<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                信號處理器會中斷主程序的執行,直到信號處理器函數返回時,主程序從中斷處繼續執行 ![](https://box.kancloud.cn/b2a46185868c5370ecc4c6bc4b0789b2_701x418.png) 圖片來源于Linux/Unix系統編程手冊 ### 同類信號阻塞 &emsp;&emsp;在執行某信號的處理器函數會阻塞同類信號(即處理器函數在執行過程,如果再次產生同類型信號,會將信號標記為等待狀態,當處理器函數返回時再進行傳遞; 若有有多個,則只會傳遞一次) ### 安全性問題 &emsp;&emsp;信號處理器會中斷主程序運行,然后變成兩條獨立的線程(信號處理器和主程序),兩條線程對全局變量的修改會相互影響對方,這就是所謂的不安全;(問題是既 然中斷了主程序執行,那么兩個線程應該是不會同時調用某個函數或修改某個全局變量啊???原來是執行到一半的時候被中斷了,額...,還是不懂...) 如何規避? - 確保信號處理器函數使用可重入函數和異步信號安全函數 - 在主程序執行不安全函數時,阻塞信號的傳遞(借助于sigprocmask函數) #### 重置errno問題 由于信號器處理器會修改errno的值,從而影響到主程序的errno,解決方法在入口處保存errno,在返回時恢復errno舊值 ```c void handler(int sig) { int oldErrno = errno; // do something errno = oldErrno; } ``` ### 全局變量聲明 ```c volatile sig_atomic_t flag ``` - 主程序和信號處理器函數共享全局變量,聲明變量的時候使用volatile關鍵字 - sig_atomic_t整數數據類型,作用是保證讀寫操作的原子性 ### 終止信號處理器其他方法 - 使用_exit()退出進程,不要使用exit(),exit()不是安全函數,它在調用_exit()函數之前會刷新stdio的緩沖區(是不是會刷新主程序的緩沖區??) ### 備選棧處理信號 &emsp;&emsp;一般是內存不夠了,才會需要備選棧的情況,先忽略它,有需要在回頭總結下 todo review ### 非本地跳轉技術 &emsp;&emsp;非本地跳轉即從信號處理器跳轉到主程序?實在看不懂,先跳過... ```c #include <setjmp.h> sigsetjump(sigjmp_buf env, int savesigs) siglongjump(sigjmp_buf env, int val) // return 0 on initial call, nonzero on return via siglongjump() ``` - savesigs不為0,會將當前信號掩碼添加到env中,之后可以通過siglongjump恢復 - 需要宏定義USE_SIGSETJMP ### SA_SIGINFO 由上一節我們知道sigaction結構有一個位掩碼flags,當sigaction.flags=SA_SIGINFO時,可以傳遞更多的信號信息;例如信號處理器攜帶了額外信息,同時信號處 理器應該聲明如下: ```c void handler(int sig, siginfo_t *siginfo, void *context); ``` 相對的,sigaction的結構多一個sa_sigaction字段,如下: ```c struct sigaction { union { void (*sa_hander)(int); void (*sa_sigaction)(int,siginfo_t *,void *); }, sigset_t sa_mask; // 信號掩碼 int flags; // 位掩碼,標識信號處理器的行為 void (*sa_restorer)(void) } ``` 要獲取signal.h對siginfo_t的聲明,需要將特性測試宏_POSIX_C_SOURCE的值定義為大于或等于199309,siginfo結構如下: ![](https://box.kancloud.cn/40e0fcb7d496c01932b80f2cc2625898_794x451.png) 重點關注下面幾個: - si_value包含調用sigqueue發送信號伴隨的數據 - si_pid發送進程id - si_fd包含于io相關的文件描述符號 - si_code信號來源;例如通過sigqueue發送的實時信號,該字段為SI_QUEUE ### 系統調用中斷和重啟 &emsp;&emsp;如果有一個阻塞的系統調用,當信號來傳遞過來時,主程序被中斷,當信號處理器完成返回時,系統調用失敗,并將errno設置為EINTR;如果要繼續運行主程序,可以將sigaction.flags設置SA_RESTART(所謂的重啟是主程序從中斷處繼續執行還是整個主程序重啟?) ### 信號同步產生和異步產生 - 同步信號,執行進程知道信號產生的時機,例如執行進程調用raise()向自己發送一個信號 - 異步信號,執行進程不知道信號產生的時機,例如信號是由內核或其他進程發出的 ### 信號傳遞時機和順序 &emsp;&emsp;當進程解除對一組等待標準信號的阻塞的時候,與各個信號產生時機先后無關,等待信號會根據信號編號從小到大優先傳遞;執行流程如下: ![](https://box.kancloud.cn/c9497040909bf7dc228c84fcc241c5f1_613x405.png) ### 實時信號 實時信號和標準信號的區別: - 標準信號編號為1~31,而實時信號為32~63 - 同類型信號被阻塞時產生多次,當解除阻塞時,標準信號只會傳遞一次,而實時信號因為會排隊等待,可以都被傳遞 - 實時信號可以通過設置SA_SIGINFO傳遞給信號處理器額外的信息 - 一組標準信號在解除阻塞時,傳遞順序按編號升序傳遞;實時信號根據信號發送順序傳遞 - SIGRTMAX表示實時信號最大值 - SIGRTMIN表示實時信號最小值 發送實時信號如下: ```c // Returns 0 on success , or -1 on error sigqueue(pid_t pid, int sig, const union sigval value) // union sigval union sigval { int sival_int; // 保存整數 void *sival_ptr; // 一個指針(一般用不到) } ``` 排隊信號數量有限制,當sigqueue發送數量超過這個限制,調用失敗并會設置errno為EAGAIN,表示需要再次發送該信號 demo: ```c #define _POSIX_C_SOURCE 199309 #include <signal.h> #include "../tlpi_hdr.h" int main(int argc, char const *argv[]) { union sigval sv; pid_t pid; int sig, num, value; if (argc < 4 || strcmp(argv[1], "--help") == 0) { usageErr("%s pid sig value [num]\n", argv[0]); } printf("%s: pid: %ld; uid: %ld\n", argv[0], (long)getpid(), (long)getuid()); pid = getLong(argv[1], GN_GT_0, "pid"); sig = getInt(argv[2], GN_GT_0, "sig"); value = getInt(argv[3], 0, "value"); num = argc > 4 ? getInt(argv[4], GN_GT_0, "num") : 1; for (int i = 0; i < num; ++i) { sv.sival_int = value + i; if (sigqueue(pid, sig, sv) == 1) { errExit("sigqueue failed \n"); } } return 0; } ``` ### 使用掩碼來等待信號sigsuspend &emsp;&emsp;使用掩碼阻塞信號,防止信號中止主程序某關鍵代碼段的執行;如果中斷處發送在解除信號和pasue掛起進程之間,會導致信號處理器返回的時候,主程序將 再次被掛起直到下一次信號到來(正常的情況是解除和掛起進程視為一個原子操作,掛起進程后接收到信號,觸發信號處理器,處理后退出進程); sigsuspend把解除信號阻塞和掛起進程封裝成一個原子操作 ```c // returns -1 with errno set to EINTR sigsuspend(sigset_t *mask) ``` - mask代替進程的信號掩碼,例如要解除某個信號,就把這個信號去掉,不要放在mask中 - 當處理器返回,sigsuspend會將進程的信號掩碼恢復到調用前的值 一個簡單的例子: ```c #define _GNU_SOURCE #include <signal.h> #include "../tlpi_hdr.h" void handler(int sig) { printf("sig %i %s\n", sig, strsignal(sig)); } int main(int argc, char const *argv[]) { struct sigaction sa; sigset_t blockMask, prevMask; printf("%s: pid:%ld; uid:%ld\n", argv[0], (long)getpid(), (long)getuid()); sigaddset(&blockMask, SIGINT); sigaddset(&blockMask, SIGQUIT); // 阻塞SIGINT和SIGQUIT,并且保留原來的信號掩碼,用于恢復 if(sigprocmask(SIG_BLOCK, &blockMask, &prevMask) == -1) { errExit("sigprocmask failed \n"); } sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = handler; if (sigaction(SIGINT, &sa, NULL) == -1) { errExit("sigaction SIGINT failed \n"); } if (sigaction(SIGQUIT, &sa, NULL) == -1) { errExit("sigaction SIGQUIT failed \n"); } // do something (不能被SIGINT和SIGQUIT信號中斷的代碼段,以sleep代替) sleep(10); // 解除信號阻塞并掛起進程 if (sigsuspend(&prevMask) == -1 && errno != EINTR) { errExit("sigsuspend failed"); } // 恢復信號掩碼 if (sigprocmask(SIG_SETMASK, &prevMask, NULL) == -1) { errExit("sigprocmask failed \n"); } return 0; } ``` ### 同步等待信號到達 ### signalfd應用 ### 問題 - 信號處理器如何中斷處于阻塞狀態的系統調用,如何重啟系統調用 ### 參考 - Linux系統編程手冊(上冊)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看