私はこの学校のプロジェクトを持っており、setjmp と longjmp を使用して不正確な計算を行うことについてです。プログラムは、シグナル ハンドラにシグナルを送るタイマーを開始します。
タイマーが切れる前に、いくつかの反復計算があります (デモ用に、何も役に立たないループだけです)。このループの最初に setjmp 呼び出しがあり、シグナル ハンドラに longjmp 呼び出しがあります。これは基本的に、ループが途中で計算を停止し、longjmp を呼び出すシグナル ハンドラを実行するように強制します。
私が抱えている問題は、計算部分が非常に短い場合は常にかなり一貫してセグメンテーション違反をしているように見えることですが、計算部分が長い場合 (内部ループに多くの反復がある場合)、問題なく実行されます (まだセグメンテーション違反に遭遇していません)。 . 明らかに、セグメンテーション違反はその計算セクションの周囲の領域で発生しているに違いありませんが、印刷ステートメントを使用する場合と同様に、デバッグによって状況が変化するため、どこから発生しているのかわかりません。
ここに私が持っているコードがあります:
#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 を使用することに同意しない人もいるかもしれませんが、これは私の教授がそうするように言った方法です。また、longjmp が呼び出された後に SIGALRM のブロックを解除することに注意してください (main の else ステートメントを参照)。
dmesg を見ると、次のようになります。
[121395.233842] cppapplication_[17397]:
segfault at 2 ip b74656f6 sp bfbb5abc
error 6 in libc-2.12.1.so[b743b000+157000
]