参考这篇文章:
http://www.cnblogs.com/mickole/p/3191832.html
《linux系统编程之信号(七):被信号中断的系统调用和库函数处理方式》
一些IO系统调用执行时, 如 read 等待输入期间, 如果收到一个信号,系统将中断read, 转而执行信号处理函数. 当信号处理返回后, 系统遇到了一个问题: 是重新开始这个系统调用, 还是让系统调用失败?
早期UNIX系统的做法是, 中断系统调用, 并让系统调用失败, 比如read返回 -1, 同时设置 errno 为 EINTR中断了的系统调用是没有完成的调用, 它的失败是临时性的, 如果再次调用则可能成功, 这并不是真正的失败, 所以要对这种情况进行处理, 典型的方式为:
while (1) { n = read(fd, buf, BUFSIZ); if (n == -1 && errno != EINTR) { printf("read error\n"); break; } if (n == 0) { printf("read done\n"); break; } }
这样做逻辑比较繁琐, 事实上, 我们可以从信号的角度来解决这个问题, 安装信号的时候, 设置 SA_RESTART属性, 那么当信号处理函数返回后, 被该信号中断的系统调用将自动恢复.
#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <error.h> #include <string.h> #include <unistd.h> void sig_handler(int signum) { printf("in handler\n"); sleep(1); printf("handler return\n"); } int main(int argc, char **argv) { char buf[100]; int ret; struct sigaction action, old_action; action.sa_handler = sig_handler; sigemptyset(&action.sa_mask); action.sa_flags = 0; /* 版本1:不设置SA_RESTART属性 * 版本2:设置SA_RESTART属性 */ //action.sa_flags |= SA_RESTART; sigaction(SIGINT, NULL, &old_action); if (old_action.sa_handler != SIG_IGN) { sigaction(SIGINT, &action, NULL); } bzero(buf, 100); ret = read(0, buf, 100); if (ret == -1) { perror("read"); } printf("read %d bytes:\n", ret); printf("%s\n", buf); return 0; }