首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C-优雅地中断msgrcv系统调用

C-优雅地中断msgrcv系统调用
EN

Stack Overflow用户
提问于 2015-03-25 00:43:32
回答 2查看 2.2K关注 0票数 1

我正在编写一个程序,它应该像服务器一样工作,并不断地从消息队列中读取并处理接收到的消息。

主循环如下所示:

代码语言:javascript
复制
while (1) {
    /* Receive message */
    if (msgrcv(msqid, &msg, sizeof(struct msgbuffer) - sizeof(long), 0, 0) == -1) {
        perror("msgrcv");
        exit(1);
    }
    //more code here
}

我遇到的问题是,如果不依赖客户机向服务器发送一条指示应该停止的消息,我就无法找到一种体面地退出这个循环的方法。我在循环之后做了很多资源清理,而我的代码永远无法到达那个点,因为循环不会结束。

我试着做的一件事就是听一个SIGINT来结束循环.

代码语言:javascript
复制
volatile sig_atomic_t stop;

void end(int signum) {
    stop = 1;
}

int main(int argc, char* argv[]) {
    signal(SIGINT, end);
    //some code
    while (!stop) {
        /* Receive message */
        if (msgrcv(msqid, &msg, sizeof(struct msgbuffer) - sizeof(long), 0, 0) == -1) {
            perror("msgrcv");
            exit(1);
        }
        //more code here
    }
    //cleanup
}

...but,因为循环挂在系统调用本身上,这不起作用,只会导致perror打印出msgrcv: Interrupted system call,而不是终止循环和清理我的资源。

有什么方法可以终止系统调用并优雅地退出循环?

解决方案:

多亏了利维美,我才能解决我的问题。以下是我为使它发挥作用所做的工作:

代码语言:javascript
复制
volatile sig_atomic_t stop;

void end(int signum) {
    stop = 1;
}

int main(int argc, char* argv[]) {
    signal(SIGINT, end);
    //some code
    while (!stop) {
        /* Receive message */
        if (msgrcv(msqid, &msg, sizeof(struct msgbuffer) - sizeof(long), 0, 0) == -1) {
            if (errno == EINTR) break;
            else {
                perror("msgrcv");
                exit(1);
            }
        }
        //more code here
    }
    //I can now reach this code segment
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-03-25 00:50:58

你最好看看现有的软件,它是一种非常常见的模式,不像你希望的那么简单。然而,基本要素是:

  • 信号处理程序-它不会有帮助(就像你发现的那样)
  • 检查从msgrcv() == EINTR返回的errno;如果是,您已经看到了一个中断。
  • 请注意,如果msgrcv在中断时收到了一些但不是所有的消息,则必须同时清理您自己的状态和发送方。
  • 最后,您可能会发现,有时会调用信号处理程序--如果中断发生在用户代码运行而不是系统调用时。而且msgrcv不是唯一的系统呼叫..。我确实说过这很复杂。

对于一个非平凡的程序,你会更好地使用这个“毒药”的方法来杀死循环。用msgsend给自己发一条消息说杀了我。这样,你就能得到可预见的结果。

鲁思

票数 1
EN

Stack Overflow用户

发布于 2015-03-25 04:59:06

代码语言:javascript
复制
the code could have the following implemented:

have the msgflg parameter contain 'IPC_NOWAIT'
then, the next line in the code should check 'errno'
for the value 'EAGIN'  
when errno is EAGIN,  either loop to recall msgrcv() or exit
    the loop due to some other criteria.
    optionally the code could nanosleep() for a while
    before jumping back to the top of the loop

extracted from the man page for msgrcv()

"EAGAIN No message was available in the queue
        and IPC_NOWAIT was  specified in msgflg."
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29245596

复制
相关文章

相似问题

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