博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
被信号中断的系统调用
阅读量:4961 次
发布时间:2019-06-12

本文共 2409 字,大约阅读时间需要 8 分钟。

被信号中断的系统调用

1:EINTR

  一般来说, 一个阻塞的慢系统调用(ex: read, write)被信号中断后, 有以下几种情况.

  1.1 按照信号默认的处理方式, 如本进程直接退出

  1.2 如果有信号处理函数, 系统调用返回-1(一般的错误返回), 且errno的值被系统置为EINTR(数值为4), 这时并不表示系统调用失败, 应该要重启系统调用

2:重启系统调用

  所谓重启系统调用, 就是某个系统调用执行期间被某个信号中断, 但系统调用不立即返回错误, 而是重启, 重启系统调用就是设置某个信号的SA_RESTART标志, 被此信号中断的系统调用将重启而不是返回错误, 但SA_RESTART标志并不是对所有的系统调用都有效。

  2.1 设置SA_RESTART

#include 
#include
#include
#include
#include
void int_handler(int signo){ printf("Got SIGINT signal\n");}int main(int argc, char const *argv[]){ char buf[1024] = {
0}; int n; struct sigaction act, oldact; act.sa_handler = int_handler; sigemptyset(&act.sa_mask); act.sa_flags |= SA_RESTART; sigaction(SIGINT, &act, &oldact); while(1){ memset(buf, 0, sizeof buf); if((n = read(STDIN_FILENO, buf, sizeof buf)) < 0){ if(errno == EINTR){
// 等待终端输入时被SIGINT中断 perror("read interrupt by sigint"); continue; } } if(buf[0] == 'q' || buf[0] == 'Q') break; printf("Got:%s\n", buf); } sigaction(SIGINT, &oldact, NULL); return 0;}

结果及分析:

stone@cdWSCMPL07:~/test_my$ ./read ^CGot SIGINT signal^CGot SIGINT signal^CGot SIGINT signal^CGot SIGINT signal^CGot SIGINT signal^CGot SIGINT signal^CGot SIGINT signal^CGot SIGINT signalqstone@cdWSCMPL07:~/test_my$

  如上, read函数在阻塞过程中被SIGINT中断, 因为信号SIGINT设置了SA_RESTART标志的原因, 所以程序仅仅执行了信号处理函数, read函数并没有返回, 而被重启并进入下一次阻塞。

  2.2 取消设置SA_RESTART

  将语句 act.sa_flags |= SA_RESTART; 屏蔽

结果及分析:

stone@cdWSCMPL07:~/test_my$ ./read ^CGot SIGINT signalread interrupt by sigint: Interrupted system call^CGot SIGINT signalread interrupt by sigint: Interrupted system call^CGot SIGINT signalread interrupt by sigint: Interrupted system call^CGot SIGINT signalread interrupt by sigint: Interrupted system callqstone@cdWSCMPL07:~/test_my$

  如上, 没有设置SA_RESTART的read被中断, read返回之后系统设置了errno, 并执行了perror打印, 最后continue后重新调用read进入下一次阻塞。

3:SA_RESTART标志的适用范围

  并不是所有的系统调用都是支援SA_RESTART重启机制的, 所以要注意区分使用范围

  支援此标志的系统调用有:

    读写IO:read, readv, write, writev, ioctl

  不支持的如select

4:总结

  对于SA_RESTART还是应该避免使用, 因为首先你要区别哪些系统调用支援哪些不支援, 这是一个比较麻烦的事情, 而且你需要对每个信号都设置此标志, 总的来讲, SA_RESTART标志是一个不建议使用的标志, 最合理的是将系统调用返回-1且errno=EINTR不纳入调用出错来考虑, 这种情况应该重新执行之前的代码来替代SA_RESTART重启系统调用。

转载于:https://www.cnblogs.com/Flychown/p/7716408.html

你可能感兴趣的文章
sigar
查看>>
iOS7自定义statusbar和navigationbar的若干问题
查看>>
[Locked] Wiggle Sort
查看>>
deque
查看>>
Setting up a Passive FTP Server in Windows Azure VM(ReplyCode: 227, Entering Passive Mode )
查看>>
Python模块调用
查看>>
委托的调用
查看>>
c#中从string数组转换到int数组
查看>>
数据模型(LP32 ILP32 LP64 LLP64 ILP64 )
查看>>
java小技巧
查看>>
POJ 3204 Ikki's Story I - Road Reconstruction
查看>>
【BZOJ】2959: 长跑(lct+缩点)(暂时弃坑)
查看>>
iOS 加载图片选择imageNamed 方法还是 imageWithContentsOfFile?
查看>>
toad for oracle中文显示乱码
查看>>
SQL中Group By的使用
查看>>
错误org/aopalliance/intercept/MethodInterceptor解决方法
查看>>
Pylint在项目中的使用
查看>>
使用nginx做反向代理和负载均衡效果图
查看>>
access remote libvirtd
查看>>
(4) Orchard 开发之 Page 的信息存在哪?
查看>>