Android C++系列:Linux信號(三)

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"可重入函數","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/e6/e6fbc0289ac5754f400a14557854942a.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不含全局變量和靜態變量是可重入函數的一個要素","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可重入函數見man 7 signal","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在信號捕捉函數裏應使用可重入函數","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在信號捕捉函數裏禁止調用不可重入函數","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"例如:strtok就是一個不可重入函數,因爲strtok內部維護了一個內部靜態指針,保存上一 次切割到的位置,如果信號的捕捉函數中也去調用strtok函數,則會造成切割字符串混亂, 應用strtok_r版本,r表示可重入。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"信號引起的競態和異步I/O","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"時序競態","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"int pause(void) ","attrs":{}}],"attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使調用進程掛起,直到有信號遞達,如果遞達信號是忽略,則繼續掛起","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"int sigsuspend(const sigset_t *mask) ","attrs":{}}],"attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以通過指定mask來臨時解除對某個信號的屏蔽,","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然後掛起等待,","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當被信號喚醒sigsuspend返回時,進程的信號屏蔽字恢復爲原來的值","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"mysleep實現,這種實現方式是否存在BUG?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"#include \n#include \n#include \nvoid sig_alrm(int signo) {\n /* nothing to do */ \n}\nunsigned int mysleep(unsigned int nsecs) {\n struct sigaction newact, oldact; \n unsigned int unslept;\n newact.sa_handler = sig_alrm; \n sigemptyset(&newact.sa_mask); \n newact.sa_flags = 0; \n sigaction(SIGALRM, &newact, &oldact);\n alarm(nsecs); \n pause();\n unslept = alarm(0); \n sigaction(SIGALRM, &oldact, NULL);\n return unslept; \n }\nint main(void) {\n while(1){\n mysleep(2);\n printf(\"Two seconds passed\\n\"); \n }\n return 0; \n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"mysleep改進版","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"unsigned int mysleep(unsigned int nsecs) {\n struct sigaction newact, oldact;\n sigset_t newmask, oldmask, suspmask;\n unsigned int unslept;\n /* set our handler,save previous information */\n newact.sa_handler = sig_alrm;\n sigemptyset(&newact.sa_mask); \n newact.sa_flags = 0; \n sigaction(SIGALRM, &newact, &oldact);\n /* block SIGALRM and save current signal mask */ \n sigemptyset(&newmask);\n sigaddset(&newmask, SIGALRM); \n sigprocmask(SIG_BLOCK, &newmask, &oldmask);\n alarm(nsecs);\n suspmask = oldmask; \n sigdelset(&suspmask, SIGALRM); /* make sure SIGALRM isn't blocked */ \n sigsuspend(&suspmask);/* wait for any signal to be caught */\n /* some signal has been caught,SIGALRM is now blocked */\n unslept = alarm(0);\n sigaction(SIGALRM, &oldact, NULL);/* reset previous action */\n \n /* reset signal mask, which unblocks SIGALRM */ \n sigprocmask(SIG_SETMASK, &oldmask, NULL); \n return(unslept);\n}\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"全局變量異步I/O","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"可重入函數","attrs":{}}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"不含全局變量和靜態變量是可重入函數的一個要素","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"可重入函數見man 7 signal","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"在信號捕捉函數裏應使用可重入函數","attrs":{}}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"避免異步I/O的類型","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"sig_atomic_t 平臺下的原子類型","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"volatile 防止編譯器開啓優化選項時,優化對內存的讀寫","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"SIGCHLD信號處理","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"SIGCHLD的產生條件","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"子進程終止時","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"子進程接收到SIGSTOP信號停止時","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"子進程處在停止態,接受到SIGCONT後喚醒時","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代碼實現","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid sys_err(char *str) {\n perror(str);\n exit(1); \n}\nvoid do_sig_child(int signo) {\n int status;\n pid_t pid;\n while ((pid = waitpid(0, &status, WNOHANG)) > 0) {\n if (WIFEXITED(status))\n printf(\"child %d exit %d\\n\", pid, WEXITSTATUS(status));\n else if (WIFSIGNALED(status))\n printf(\"child %d cancel signal %d\\n\", pid, WTERMSIG(status));\n }\n}\nint main(void) {\n pid_t pid;\n int i;\n //阻塞SIGCHLD\n for (i = 0; i < 10; i++) {\n if ((pid = fork()) == 0) \n break;\n else if (pid < 0) \n sys_err(\"fork\");\n }\n if (pid == 0) {\n int n = 18; while (n--) {\n printf(\"child ID %d\\n\", getpid());\n sleep(1); \n }\n return i; \n }else if (pid > 0) { //先設置捕捉\n //再解除對SIGCHLD的阻塞 \n struct sigaction act;\n act.sa_handler = do_sig_child; \n sigemptyset(&act.sa_mask); act.sa_flags = 0; \n sigaction(SIGCHLD, &act, NULL); \n while (1) {\n printf(\"Parent ID %d\\n\", getpid());\n sleep(1); \n }\n }\n return 0; \n}\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"status處理方式","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"pid_t waitpid(pid_t pid, int *status, int options) ","attrs":{}}],"attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"options","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"WNOHANG 沒有子進程結束,立即返回","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"WUNTRACED","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果子進程由於被停止產生的SIGCHLD, waitpid則立即返回","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"WCONTINUED 如果子進程由於被SIGCONT喚醒而產生的SIGCHLD, waitpid則立即返回","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"獲取status","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"WIFEXITED(status) 子進程正常exit終止,返回真 WEXITSTATUS(status)返回子進程正常退出值","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"WIFSIGNALED(status) 子進程被信號終止,返回真","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"WTERMSIG(status)返回終止子進程的信號值 WIFSTOPPED(status)","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"子進程被停止,返回真 WSTOPSIG(status)返回停止子進程的信號值","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"WIFCONTINUED(status) 子進程由停止態轉爲就緒態,返回真","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"向信號捕捉函數傳參","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"sigqueue","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"int sigqueue(pid_t pid, int sig, const union sigval value) union sigval {\nint sival_int;\nvoid *sival_ptr; };\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"sigaction","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"void (*sa_sigaction)(int, siginfo_t *, void *) \nsiginfo_t {\n int si_int; \n void *si_ptr; \n sigval_t si_value;\n ...\n}\nsa_flags = SA_SIGINFO\n/* POSIX.1b signal */ /* POSIX.1b signal */ /* Signal value */\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"實例","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"進程自己收發信號,在同一地址空間","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不同進程間收發信號,不在同一地址空間,不適合傳地址","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"信號中斷系統調用","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"read阻塞時,信號中斷系統調用:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"返回部分讀到的數據","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"read調用失敗,errno設成EINTER","attrs":{}}]}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文介紹了可重入函數,信號引起的競態和異步I/O,SIGCHLD信號處理,向想好捕捉函數傳參,信號中斷系統調用。","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章