msgrcv – SA_RESTART标志不起作用

我的代码使用IPC队列在线程之间进行通信有问题。 我需要安全地处理SIGINT – 让程序在关闭之前出现SIGINT时完成所有活动线程。 虽然,我有找到解决方案的严重问题,因为即使对带有标志SA_RESTART的SIGINT进行sigaction,msgrcv函数也会出现EINTR错误。

我的问题是 – 有没有办法避免使用msgrcv函数的EINTR,而不是在某些“if”中指定错误条件,例如:

if (msgrcv<0){ if (errno == EINTR){ errno = 0; } } 

这是我的程序的简化版本,用于演示问题:

 #include  #include  #include  #include  #define IPC_KEY 11000 #define BUF_SIZE 128 //structure of IPC message typedef struct msgbuf{ long mtype; char mtext[BUF_SIZE]; } message_buf; void handle_sigint(int sig){ signal(SIGINT,SIG_IGN); /* some operation to handle sigint, here it's really simple setting SIGINT to be ignored */ } int main(){ long ipc_id; message_buf msg; struct sigaction setup_action; sigset_t block_mask; //setup sigaction for SIGINT sigemptyset(&block_mask); sigaddset(&block_mask,SIGINT); setup_action.sa_handler = handle_sigint; setup_action.sa_mask = block_mask; setup_action.sa_flags = SA_RESTART; if (sigaction(SIGINT, &setup_action, 0) < 0){ perror("sigaction"); exit(1); } //creating the ipc queue if ((ipc_id = msgget(IPC_KEY, IPC_CREAT | IPC_EXCL | 0666))<0){ perror("error in msgget"); exit(1); } for(;;){ if (msgrcv(ipc_id,&msg,BUF_SIZE,1,0)<0){ perror("error in msgrcv"); exit(1); } printf("received message : %s\n",msg.mtext); } } 

这是清理IPC队列的简单程序:

 #include  #include  #include  #include  #define IPC_KEY 11000 int main(){ long ipc_id; if ((ipc_id = msgget(IPC_KEY, IPC_CREAT | 0666 )) < 0) { perror("error in msgget"); exit(1); } if (msgctl(ipc_id, IPC_RMID, 0) != 0){ perror("error in msgctl"); exit(1); } return 0; } 

在此先感谢您的帮助! 我真的希望我没有提出重复的问题,但我试图寻找解决方案的一段时间,但遗憾的是除了用if函数显式捕获EINTR errno之外没有发现任何其他问题。

从(Linux)手册 :

无论是否使用SA_RESTART,以下接口在被信号处理程序中断后都不会重新启动; 当信号处理程序中断时,它们总是因错误EINTR而失败:

….

  • System V IPC接口: msgrcv(2) ,msgsnd(2),semop(2)和semtimedop(2)。

处理SA_RESTART的方式是定义的位实现。 你没有使用特定的Unix风格进行标记,但我认为你的Unix根本不遵守SA_RESTART来进行特定的系统调用。

@cnicutar在10秒内击败了我(所以+1),但是我想补充一点,你需要做的就是在do / while循环中包含对msgrcv的调用,例如

 int res; do { res = msgrcv(your parameters here); } while ((res < 0 ) && (errno == EINTR)); 

如果你经常使用msgrcv ,你当然可以定义一个微小的函数来为你做这件事。