我正在开发一个应该像服务器一样运行的程序,并不断从消息队列中读取并处理收到的消息。
主循环看起来像这样:
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
,而不是终止循环并清理我的资源。
有没有办法可以终止系统调用并优雅地退出循环?
SOLUTION:
感谢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
}
答案 0 :(得分:1)
你最好去看一下这样做的现有软件;这是一种非常普遍的模式,并不像你希望的那样简单。但基本要素是:
对于一个非平凡的计划,你最好使用毒药#39;杀死循环的方法。使用msgsend给自己发一条消息说杀了我。这样,您就可以获得可预测的结果。
HTH,露丝
答案 1 :(得分:0)
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."