C - 优雅地中断 msgrcv 系统调用
C - Gracefully interrupting msgrcv system call
我正在开发一个应该像服务器一样工作并不断从消息队列中读取并处理接收到的消息的程序。
主循环看起来像这样:
while (1) {
/* Receive message */
if (msgrcv(msqid, &msg, sizeof(struct msgbuffer) - sizeof(long), 0, 0) == -1) {
perror("msgrcv");
exit(1);
}
//more code here
}
我遇到的问题是,如果不依赖客户端向服务器发送消息指示它应该停止,我无法找到一种正常退出此循环的方法。我在循环后做了很多资源清理,我的代码永远无法到达那个点,因为循环不会结束。
我尝试做的一件事是监听 SIGINT 以结束循环....
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
}
...但是由于循环挂在系统调用本身上,所以这不起作用,只会导致 perror
打印出 msgrcv: Interrupted system call
,而不是终止循环并进行清理增加我的资源。
有什么方法可以终止系统调用并优雅地退出循环?
解决方案:
感谢 rivimey,我能够解决我的问题。这是我为使其工作所做的工作:
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
}
你最好去看看现有的执行此操作的软件;这是一种非常常见的模式,并不像您希望的那样简单。然而,基础知识是:
- 信号处理程序 - 它无济于事(如您所见)
- 检查来自 msgrcv() == EINTR 的错误号 return;如果是这样,您已经看到中断。
- 请注意,如果 msgrcv 在中断时收到了部分而非全部消息,则您将不得不清理自己的状态和发送方。
- 最后,您可能会发现有时会调用信号处理程序 - 如果中断发生在用户代码为 运行 而不是系统调用时。而且 msgrcv 不是唯一的系统调用...我确实说过它很复杂。
对于一个重要的程序,你最好使用 'poison' 终止循环的方法。使用 msgsend 向自己发送一条消息,上面写着杀了我。这样,您将获得可预测的结果。
HTH,露丝
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."
我正在开发一个应该像服务器一样工作并不断从消息队列中读取并处理接收到的消息的程序。
主循环看起来像这样:
while (1) {
/* Receive message */
if (msgrcv(msqid, &msg, sizeof(struct msgbuffer) - sizeof(long), 0, 0) == -1) {
perror("msgrcv");
exit(1);
}
//more code here
}
我遇到的问题是,如果不依赖客户端向服务器发送消息指示它应该停止,我无法找到一种正常退出此循环的方法。我在循环后做了很多资源清理,我的代码永远无法到达那个点,因为循环不会结束。
我尝试做的一件事是监听 SIGINT 以结束循环....
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
}
...但是由于循环挂在系统调用本身上,所以这不起作用,只会导致 perror
打印出 msgrcv: Interrupted system call
,而不是终止循环并进行清理增加我的资源。
有什么方法可以终止系统调用并优雅地退出循环?
解决方案:
感谢 rivimey,我能够解决我的问题。这是我为使其工作所做的工作:
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
}
你最好去看看现有的执行此操作的软件;这是一种非常常见的模式,并不像您希望的那样简单。然而,基础知识是:
- 信号处理程序 - 它无济于事(如您所见)
- 检查来自 msgrcv() == EINTR 的错误号 return;如果是这样,您已经看到中断。
- 请注意,如果 msgrcv 在中断时收到了部分而非全部消息,则您将不得不清理自己的状态和发送方。
- 最后,您可能会发现有时会调用信号处理程序 - 如果中断发生在用户代码为 运行 而不是系统调用时。而且 msgrcv 不是唯一的系统调用...我确实说过它很复杂。
对于一个重要的程序,你最好使用 'poison' 终止循环的方法。使用 msgsend 向自己发送一条消息,上面写着杀了我。这样,您将获得可预测的结果。
HTH,露丝
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."