首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >msgrcv - SA_RESTART标志不工作

msgrcv - SA_RESTART标志不工作
EN

Stack Overflow用户
提问于 2014-12-20 22:50:45
回答 2查看 4.7K关注 0票数 3

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

我的问题是-除了在某些"if“中指定错误条件之外,还有什么方法可以避免使用msgrcv函数的EINTR,例如:

代码语言:javascript
复制
if (msgrcv<0){
  if (errno == EINTR){
    errno = 0;
  }
}

下面是我的程序的简化版本,以说明问题:

代码语言:javascript
复制
#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队列的简单程序:

代码语言:javascript
复制
#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函数捕获errno之外,没有找到任何其他的解决方案。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-12-20 23:00:22

来自(Linux)手册

无论使用什么SA_RESTART,下列接口在被信号处理程序中断后都不会重新启动;当被信号处理程序中断时,它们总是会失败: ……

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

处理SA_RESTART的方式是定义了一些实现。您没有使用特定的Unix样式进行标记,但我假设您的Unix对于特定的系统调用根本不服从SA_RESTART

票数 3
EN

Stack Overflow用户

发布于 2014-12-20 23:03:46

@cnicutar比我快10秒(所以+1),但我要补充的是,您所需要做的就是将对msgrcv的调用包装在一个do/while循环中。

代码语言:javascript
复制
int res;
do
{
  res = msgrcv(your parameters here);
} while ((res < 0 ) && (errno == EINTR));

当然,如果您经常使用msgrcv,您可以定义一个很小的函数来完成这个任务。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27585075

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档