马上加入IBC程序猿 各种源码随意下,各种教程随便看! 注册 每日签到 加入编程讨论群

C#教程 ASP.NET教程 C#视频教程程序源码享受不尽 C#技术求助 ASP.NET技术求助

【源码下载】 社群合作 申请版主 程序开发 【远程协助】 每天乐一乐 每日签到 【承接外包项目】 面试-葵花宝典下载

官方一群:

官方二群:

Linux被中断的系统调用

[复制链接]
查看1876 | 回复1 | 2019-10-12 10:22:37 | 显示全部楼层 |阅读模式

慢系统调用,指的是可能永远无法返回,从而使进程永远壅闭的系统调用,好比无客户毗连时的accept、无输入时的read都属于慢速系统调用。
在Linux中,当壅闭于某个慢系统调用的进程捕获一个信号,则该系统调用就会被停止,转而实行信号处置惩罚函数,这就是被停止的系统调用。
然而,当信号处置惩罚函数返回时,有可能发生以下的情况:

  • 如果信号处置惩罚函数是用signal注册的,系统调用会自动重启,函数不会返回
  • 如果信号处置惩罚函数是用sigaction注册的
    • 默认情况下,系统调用不会自动重启,函数将返回失败,同时errno被置为EINTR
    • 只有停止信号的SA_RESTART标记有效时,系统调用才会自动重启

下面我们编写代码,分别验证上述几种情况,此中系统调用选择read,停止信号选择SIGALRM,停止信号由alarm产生。

利用signal

  1. <code>#include <stdio.h>
  2. #include <signal.h>
  3. #include <unistd.h>
  4. #include <errno.h>
  5. void handler(int s)
  6. {
  7. printf("read is interrupt by signal handler\n");
  8. return;
  9. }
  10. int main()
  11. {
  12. char buf[10];
  13. int nread = 0;
  14. signal(SIGALRM, handler);
  15. alarm(2);
  16. printf("read start\n");
  17. nread = read(STDIN_FILENO, buf, sizeof(buf));
  18. printf("read return\n");
  19. if ((nread < 0) && (errno == EINTR))
  20. {
  21. printf("read return failed, errno is EINTR\n");
  22. }
  23. return 0;
  24. }</code>
复制代码

102237a870ssoo93o7o440.png

利用sigaction + 默认情况

  1. <code>#include <stdio.h>
  2. #include <signal.h>
  3. #include <unistd.h>
  4. #include <errno.h>
  5. void handler(int s)
  6. {
  7. printf("read is interrupt by signal handler\n");
  8. return;
  9. }
  10. int main()
  11. {
  12. char buf[10];
  13. int nread = 0;
  14. struct sigaction act;
  15. sigemptyset(&act.sa_mask);
  16. act.sa_handler = handler;
  17. act.sa_flags = 0; //不给SIGALRM信号设置SA_RESTART标记,利用sigaction的默认处置惩罚方式
  18. //act.sa_flag |= SA_INTERRUPT; //SA_INTERRUPT是sigaction的默认处置惩罚方式,即不自动重启被停止的系统调用
  19. //实际上,不管act.sa_flags值为多少,只要不设置SA_RESTART,sigaction都是按SA_INTERRUPT处置惩罚的
  20. sigaction(SIGALRM, &act, NULL);
  21. alarm(2);
  22. printf("read start\n");
  23. nread = read(STDIN_FILENO, buf, sizeof(buf));
  24. printf("read return\n");
  25. if ((nread < 0) && (errno == EINTR))
  26. {
  27. printf("read return failed, errno is EINTR\n");
  28. }
  29. return 0;
  30. }</code>
复制代码

102237e1g2o889g64w44c5.png

利用sigaction + 指定SA_RESTART标记

  1. <code>#include <stdio.h>
  2. #include <signal.h>
  3. #include <unistd.h>
  4. #include <errno.h>
  5. void handler(int s)
  6. {
  7. printf("read is interrupt by signal handler\n");
  8. return;
  9. }
  10. int main()
  11. {
  12. char buf[10];
  13. int nread = 0;
  14. struct sigaction act;
  15. sigemptyset(&act.sa_mask);
  16. act.sa_handler = handler;
  17. act.sa_flags = 0;
  18. act.sa_flags |= SA_RESTART; //给SIGALRM信号设置SA_RESTART标记
  19. sigaction(SIGALRM, &act, NULL);
  20. alarm(2);
  21. printf("read start\n");
  22. nread = read(STDIN_FILENO, buf, sizeof(buf));
  23. printf("read return\n");
  24. if ((nread < 0) && (errno == EINTR))
  25. {
  26. printf("read return failed, errno is EINTR\n");
  27. }
  28. return 0;
  29. }</code>
复制代码

102238ud69ykys0ydbryub.png

由于对被停止系统调用处置惩罚方式的差异性,因此对应用步伐来说,与被停止的系统调用相干的题目是:

  • 应用步伐无法包管总是知道信号处置惩罚函数的注册方式,以及是否设置了SA_RESTART标记
  • 可移植的代码必须显式处置惩罚关键函数的堕落返回,当函数堕落且errno等于EINTR时,可以根据实际需求举行相应处置惩罚,好比重启该函数
  1. <code>int nread = read(fd, buf, 1024);
  2. if (nread < 0)
  3. {
  4. if (errno == EINTR)
  5. {
  6. //read被停止,实在不应该算作失败,可以根据实际需求举行处置惩罚,好比重写调用read,也可以忽略它
  7. }
  8. else
  9. {
  10. //read真正的读错误
  11. }
  12. }</code>
复制代码






来源:https://www.cnblogs.com/songhe364826110/p/11657198.html
C#论坛 www.ibcibc.com IBC编程社区
C#
C#论坛
IBC编程社区
*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则