原创:
今天在嵌入式Linux中调试msgrcv时出现其返回为-1,错误代码4的错误:errno=4[Interruptedsystem call]。错误代码4为: 当进程睡眠等待接收消息时,被信号中断。 这是由于在此线程中同时使用了信号,而慢系统调用(阻塞系统调用)在使线程休眠等待时被信号唤醒,当捕获到某个信号且相应信号处理函数返回时,这个系统调用被中断,调用返回错误,设置errno为EINTR(相应的错误描述为“Interruptedsystem call”)。
网上有人说在安装信号时设置SA_RESTART属性(该方法对有的系统调用无效,在得到了验证),并忽略EINTR错误,我试了无效,最终新开了一个线程,在新的线程里处理msgrcv等msgq的操作,顺利解决了问题。
1.术语
慢系统调用可以被永久阻塞,包括以下几个类别:
2.EINTR介绍
“Interruptedsystem call”)。
系统调用函数
write
由于信号中断,没写成功任何数据。
The call was interrupted by a signal before any data was written.
open
由于信号中断,没读到任何数据。
The call was interrupted by a signal before any data was read.
recv
由于信号中断返回,没有任何数据可用。
The receive was interrupted by delivery of a signal before any data were available.
sem_wait
函数调用被信号处理函数中断。
The call was interrupted by a signal handler.
3.解决类似问题有3种方法
◆人为重启被中断的系统调用
3.1.人为重启被中断的系统调用
-1它的失败是临时性的,如果再次调用则可能成功,这并不是真正的失败,,所以要对这种情况进行处理,典型的方式为:
while((r= read(fd, buf,len))<0&&errno == EINTR);/*do nothing*/
#include poll.hint check_conn_is_ok(socket_t sock) {structpollfd fd;intret = 0;socklen_tlen = 0;fd.fd= sock;fd.events= POLLOUT;while( poll (&fd, 1, -1) == -1 ) {if(errno != EINTR ){perror("poll");return-1;}}len= sizeof(ret);if( getsockopt (sock, SOL_SOCKET, SO_ERROR,&ret,&len) == -1 ) {perror("getsockopt");return-1;}if(ret!= 0) {fprintf(stderr, "socket %d connect failed: %s\n",sock, strerror (ret));return-1;}return0;}在调用connect时,这样使用:#include erron.h….if(connnect()) { if(errno == EINTR) {if(check_conn_is_ok() < 0) {perror();return -1;}else {printf("connect issuccess!\n");} } else {perror("connect");return -1; }}3.2.设置SA_RESTART属性
我们还可以从信号的角度来解决这个问题, 安装信号的时候, 设置 SA_RESTART属性,那么当信号处理函数返回后, 不会让系统调用返回失败,而是让被该信号中断的系统调用将自动恢复。
1. struct sigaction action; 2. action.sa_handler = handler_func; 3. sigemptyset(&action.sa_mask); 4. action.sa_flags = 0; 5. /* 设置SA_RESTART属性 */ 6. action.sa_flags |= SA_RESTART; 7. sigaction(SIGALRM, &action, NULL);
和man msgrcv中就有提到这点:
msgsnd and msgrcv are never automatically restarted after being interrupted by a signal handler, regardless of the setting of the SA_RESTART flag when establishing a signal handler.
3.3.忽略信号
当然最简单的方法是忽略信号,在安装信号时,明确告诉系统不会产生该信号的中断。
struct sigaction action; action.sa_handler = SIG_IGN;sigemptyset(&action.sa_mask);sigaction(SIGALRM, &action, NULL);总结
处理方法有以下三种:①人为重启被中断的系统调用;②安装信号时设置 SA_RESTART属性;③忽略信号(让系统不产生信号中断)。
。
参考:
转载请注明:
诚实是人生绝妙的法宝。虽然对人诚实,