The APUE book says that: If the signal occurs after the test of sig_int_flag
but before the call to pause
, the process could go to sleep forever.
I don't know why, can somebody tells me? Thanks a lot.
int sig_int(); /* my signal handling function */
int sig_int_flag; /* set nonzero when signal occurs */
int main() {
signal(SIGINT, sig_int) /* establish handler */
.
.
.
while (sig_int_flag == 0)
pause(); /* go to sleep, waiting for signal */
}
int sig_int() {
signal(SIGINT, sig_int); /* reestablish handler for next time */
sig_int_flag = 1; /* set flag for main loop to examine */
}
If an interrupt signal is issued at the precise time you're describing:
1
, but too late (test has been done) pause()
is called and the program waits That said, if CTRL+C/SIGINT is triggered another time, you can exit the loop, so it's not that critical, since that signal can be issued manually.
If you want to check that behaviour, I suggest you add a sleep
statement:
while (sig_int_flag == 0)
{
printf("Hit CTRL+C in the next 10 seconds to trigger the bug\n");
sleep(10);
pause(); /* go to sleep, waiting for signal */
}
A workaround would be to remove the pause()
statement and replace it by a polling loop:
while (sig_int_flag == 0)
{
sleep(1);
}
If a SIGINT occurs anywhere in the loop, including between the while
and the sleep
, then the worse thing that can happen is that the program waits 1 second before noticing that the flag is set, then it exits the loop, and the other, more plausible case it that the sleep
call is interrupted, and the loop is exited immediately, so when the signal is set, there's little visible difference between that and a pause
call if we only expect SIGINT
.
The question's already answered. However, additional answer can consolidate the idea.
while (sig_int_flag == 0) {
<----- think it signal is caught here before pause btw while and pause()
pause(); /* go to sleep, waiting for signal */
}
Having caught, signal handler runs. After it finishes its task, it returns to a point at which the signal is caught, in main()
in this case. So, the point is pause()
and pause()
is called. It waits again SIGINT
to catch. To exemplify it, I add sleep(5)
equivalently to catch prior pause()
.
So, we typically want the second situation. To achieve it always, the aforementioned code block has to be atomic . That's why sigsuspend()
is better and should be used.
If you would like to experience the fallible case,
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
volatile sig_atomic_t sig_int_flag = 0; /* set nonzero when signal occurs */
char const * handlerMsg = "in handler\n";
int handlerMsgLen;
void sig_int(int s) {
signal(SIGINT, sig_int); /* reestablish handler for next time */
sig_int_flag = 1; /* set flag for main loop to examine */
write(2, handlerMsg, handlerMsgLen);
}
void mySleep() {
for (int i = 0; i < 5; ++i) {
sleep(1);
fprintf(stderr, "%d ", i + 1);
}
}
int main() {
handlerMsgLen = strlen(handlerMsg);
signal(SIGINT, sig_int); /* establish handler */
while (sig_int_flag == 0) {
mySleep();
pause(); /* go to sleep, waiting for signal */
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.