msgrcv - SA_RESTART标志不起作用

时间:2014-12-20 22:50:46

标签: c signals ipc

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

我的问题是 - 有没有办法避免使用msgrcv函数以外的EINTR 在某些&#34中指定错误条件;如果"如:

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

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

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/msg.h>

#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 <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/msg.h>

#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之外没有找到任何其他问题。

2 个答案:

答案 0 :(得分:3)

来自(Linux) manual

  

以下接口在被中断后永远不会重新启动   通过信号处理程序,无论使用SA_RESTART;他们总是   当被信号中断时,错误EINTR失败   处理程序:

     

...

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

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

答案 1 :(得分:2)

@cnicutar在10秒内击败了我(所以+1),但我想补充一点,你需要做的就是将msgrcv / {{} do的呼叫包裹起来1}}循环,例如

while

如果你经常使用int res; do { res = msgrcv(your parameters here); } while ((res < 0 ) && (errno == EINTR)); ,你当然可以定义一个很小的功能。