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":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章