1、什么是慢系统调用?
该术语适用于那些可能永远阻塞的系统调用 。永远阻塞的系统调用是指调用永远无法返回 , 多数网络支持函数都属于这一类 。如:若没有客户连接到服务器上 , 那么服务器的accept调用就会永远阻塞 。
慢系统调用可以被永久阻塞 , 包括以下几个类别:
(1)读写‘慢’设备(包括pipe , 终端设备 , 网络连接等) 。读时 , 数据不存在 , 需要等待;写时 , 缓冲区满或其他原因 , 需要等待 。
(2)当打开某些特殊文件时 , 需要等待某些条件 , 才能打开 。例如:打开中断设备时 , 需要等到连接设备的modem响应才能完成 。
(3)pause和wait函数 。pause函数使调用进程睡眠 , 直到捕获到一个信号 。wait等待子进程终止 。
(4)某些ioctl操作 。
(5)某些IPC操作 。
2、EINTR错误产生的原因-(阻塞的系统调用、或者非阻塞的系统调用)
如果进程在一个慢系统调用(slow system call)中阻塞时 , 当捕获到某个信号且相应信号处理函数返回时 , 这个系统调用不再阻塞而是被中断 , 就会调用返回错误(一般为-1)&&设置errno为EINTR(相应的错误描述为“Interrupted system call”) 。
如下表所示的系统调用就会产生EINTR错误 , 当然不同的函数意义也不同 。
![linux系统中socket错误码:eintr和eagain的处理方法](http://img.jiangsulong.com/220418/09522C315-0.jpg)
文章插图
3、解决办法
既然系统调用会被中断 , 那么别忘了要处理被中断的系统调用 。有三种处理方式:
解决方法1:重启被中断的系统调用
当碰到EINTR错误的时候 , 有一些可以重启的系统调用要进行重启 , 而对于有一些系统调用是不能够重启的 。例如:accept、read、write、select、和open之类的函数来说 , 是可以进行重启的 。不过对于套接字编程中的connect函数是不能重启的 , 若connect函数返回一个EINTR错误的时候 , 我们不能再次调用它 , 否则将立即返回一个错误 。针对connect不能重启的处理方法是 , 必须调用select来等待连接完成 。
理解“重启”?一些IO系统调用执行时 , 如 read 等待输入期间 , 如果收到一个信号 , 系统将中断read , 转而执行信号处理函数. 当信号处理返回后 , 系统遇到了一个问题: 是重新开始这个系统调用? 还是让系统调用失败?早期UNIX系统的做法是:中断系统调用 , 并让系统调用失败 , 比如read返回 -1 , 同时设置 errno 为EINTR中断了的系统调用是没有完成的调用 , 它的失败是临时性的 , 如果再次调用则可能成功 , 这并不是真正的失败 , 所以要对这种情况进行处理 , 典型的方式为“重启” , 采用accept函数为例子 , 代码如下
需要C/C++ linux服务器架构师学习资料私信“资料”(资料包括C/C++ , Linux , golang技术 , Nginx , ZeroMQ , MySQL , redis , fastdfs , MongoDB , ZK , 流媒体 , CDN , P2P , K8S , Docker , TCP/IP , 协程 , DPDK , ffmpeg等) , 免费分享
![linux系统中socket错误码:eintr和eagain的处理方法](http://img.jiangsulong.com/220418/0952261924-1.jpg)
文章插图
ACCEPT:clifd = accept(srvfd,(struct sockaddr*)&cliaddr,&cliaddrlen);if (clifd == -1) {if (errno == EINTR) {goto ACCEPT;} else {fprintf(stderr, "accept fail,error:%sn", strerror(errno));return -1;}}
解决方法2:安装信号时设置 SA_RESTART属性(该方法对有的系统调用无效)struct sigaction action;action.sa_handler = handler_func;sigemptyset(&action.sa_mask);action.sa_flags = 0;/* 设置SA_RESTART属性 */action.sa_flags |= SA_RESTART;sigaction(SIGALRM, &action, NULL);
解决方法3: 忽略信号(让系统不产生信号中断)struct sigaction action;action.sa_handler = SIG_IGN;sigemptyset(&action.sa_mask);sigaction(SIGALRM, &action, NULL);
EAGAIN-(一般用于非阻塞的系统调用)非阻塞的系统调用 , 由于资源限制/不满足条件 , 导致返回值为EAGAIN
在Linux环境下开发经常会碰到很多错误(设置errno) , 其中EAGAIN是其中比较常见的一个错误(比如用在非阻塞操作中) 。
推荐阅读
- 台当局大惊!台“中科院”采购服务器可将资料传至百度云
- 智能音箱“惊魂记”:夜半歌声、声音盗刷、暗中窃听
- 苹果电脑装了windows系统怎么恢复原来系统?苹果电脑重装系统windows还在吗?
- Linuxfx - 这套Linux操作系统看起来和Windows 10非常类似
- 软件系统稳定性设计的秘密
- excel中快速输入√与×并自动标注颜色,你不会,同事1分钟就搞定
- 熟地的药用价值有哪些
- 天南星药用价值有哪些
- 五加皮药用价值有哪些呢
- 植物药用价值有哪些