У меня есть этот школьный проект, и он использует setjmp и longjmp для неточных расчетов.Программа запускает таймер, который будет сигнализировать обработчику сигнала.
Перед истечением таймера, есть некоторые итерационные вычисления (для демонстрационных целей, просто цикл, который не делает ничего полезного).В начале этого цикла происходит вызов setjmp, а в обработчике сигнала - вызов longjmp.Это в основном заставляет цикл останавливать вычисление в середине и запускать обработчик сигнала там, где он вызывает longjmp.
Проблема, с которой я сталкиваюсь, заключается в том, что всякий раз, когда часть вычисления очень короткая, я, кажется, достаточно последовательно перестаю работать, однако, когда часть вычисления длинная (внутренний цикл имеет много итераций), она работает очень хорошо (нестолкнуться с segfault еще).Очевидно, что segfault должен происходить в областях, окружающих этот раздел вычислений, но я не могу понять, откуда он исходит, так как отладка меняет вещи так же, как и с помощью операторов print.
Вот код, который у меня есть:
#include <iostream>
#include <signal.h>
#include <sys/time.h>
#include <setjmp.h>
#include <errno.h>
#include <stdlib.h>
jmp_buf env;
static void usr_timer_tick(int signal)
{
if(signal == SIGALRM)
{
longjmp(env, 1);
}
}
/*Program Description
* This program first sets up the timer to signal usr_timer_tick
* every 1 second on the SIGALRM signal. It then proceeds to do an iterated calculation three times.
* An infinite loop calls setjmp and when 0 is returned, continues doing
* a calculation on temp. After an iteration is complete, the result of
* the iteration is saved into finalResult after blocking SIGALRM to
* make the saving of the result atomic.
*
* Once the signal handler(usr_timer_tick) is triggered, it calls longjmp which forces
* setjmp to return a non-zero value, which causes the main function to break out
* of the infinite loop and start a new calculation...this is done a total of 3
* times for demonstration purposes.
*/
int main(int argc, char **argv)
{
//init timer using setitimer..real mode
int which = ITIMER_REAL;
struct itimerval value;
struct sigaction sact;
sigset_t newmask, oldmask;
sigemptyset( &newmask );
sigemptyset( &oldmask );
sigaddset(&newmask, SIGALRM);
sact.sa_flags = 0;
sact.sa_handler = usr_timer_tick;
sigaction( SIGALRM, &sact, NULL );
// value.it_interval.tv_sec = 0; /* One second */
// value.it_interval.tv_usec = 0;
// value.it_value.tv_sec = 1; /* One second */
// value.it_value.tv_usec = 0;
//
// setitimer(which, &value, NULL);
double finalResult = 0;
int loopcount = 0;
double tempResult = 0;
for(int j = 0; j < 10; j++)
{
loopcount = 0;
std::cout << "Run " << j << " begin loop "
<< loopcount << "\n";
if(setjmp(env) == 0)
{ //timer not hit yet
//sigprocmask(SIG_BLOCK, &newmask, NULL);
value.it_interval.tv_sec = 0; /* One second */
value.it_interval.tv_usec = 0;
value.it_value.tv_sec = 1; /* One second */
value.it_value.tv_usec = 0;
setitimer(which, &value, NULL);
//sigprocmask(SIG_SETMASK, &oldmask, NULL);
for(;;)
{
//Do some random calculations
for(int i = 0; i < 1; i++)
{
tempResult = tempResult + .001;
}
//block signal from arriving and save to finalResult
if(sigprocmask(SIG_BLOCK, &newmask, NULL) < 0) exit(-1);
finalResult = tempResult;
std::cout << "Run " << j << " complete loop "
<< loopcount << " result = " << finalResult<< "\n";
loopcount++;
if(sigprocmask(SIG_SETMASK, &oldmask, NULL)< 0) exit(errno);
}
}
else
{
//timer signal arrived, print the final result and get out of loop
std::cout << "***Run " << j << " killed on loop "
<< loopcount << " result = "<< finalResult << "\n";
sigprocmask(SIG_SETMASK, &oldmask, NULL);
//break;
}
}
return 0;
}
Я понимаю, что некоторые из вас, возможно, не согласятся с тем, что longjmp следует использовать в обработчике сигналов, но именно так сказал мой профессор.Также следует заметить, что я разблокирую SIGALRM после вызова longjmp (см. Еще оператор main).
Глядя на dmesg, я получаю:
[121395.233842] cppapplication_[17397]:
segfault at 2 ip b74656f6 sp bfbb5abc
error 6 in libc-2.12.1.so[b743b000+157000
]