C++ 通过sigsetjmp和longsetjmp恢复环境
我将sigsetjmp和singlongjmp与sigallarm结合使用来中断系统调用,如下代码所示C++ 通过sigsetjmp和longsetjmp恢复环境,c++,context-switch,C++,Context Switch,我将sigsetjmp和singlongjmp与sigallarm结合使用来中断系统调用,如下代码所示 //data of Alarm_interrupter void (TClass::*fpt)(const char*); // pointer to member function TClass* pt2Object; // pointer to object ===============================================
//data of Alarm_interrupter
void (TClass::*fpt)(const char*); // pointer to member function
TClass* pt2Object; // pointer to object
===================================================
//for timeout processing
static sigjmp_buf jmpbuf;
static void recvfrom_alarm(int) {
siglongjmp(jmpbuf, 1);
}
======================================================
void Alarm_interrupter::start_timeout() {
signal(SIGALRM, recvfrom_alarm);
alarm(timeout);
(*pt2Object.*fpt)("timeouted before sigsetjmp"); //this call works OK
if (sigsetjmp(jmpbuf,1) != 0) {
//at this point, pt2Object is still OK,
//but fpt seems to point to nothign.
(*pt2Object.*fpt)("timeouted after sigsetjmp");
}
return;
}
==============================================================
在sigsetjmp return 1之前,使用对象和方法指针的调用:*pt2Object.*fpt(“sigsetjmp之前的timeouted”)是正常的,但在sigsetjmp return 1之后,此调用失败。
在检查变量的状态之后,我注意到对象指针“pt2Object”仍然正常,但方法指针“fpt”似乎有所不同
我认为其中一个可能的原因是sigsetjmp无法恢复整个早期环境,其中包括方法指针“fpt”
你们能帮我解决这个问题吗。非常感谢 正如Potatoswatter指出的那样,使用报警延迟
longjmp
太聪明了,不值得依赖。你必须先调用'sigsetjmp'。在你试图返回那里之前,它必须发生
sigsetjmp
或setjmp
的唯一工作方式是遵循此伪代码
if (sigsetjmp(...) != 0) {
// Error handling code
}
// code that might call siglongjmp to bail out to Error handling code
要执行上下文的保存,必须执行一次。这将初始化jmpbuf
。如果在执行之前没有调用setjmp
而调用longjmp
,则无法预测行为
另外,longjmp
将倾向于删除您可能尝试使用的任何局部变量
int var = 3;
var = 2;
if (sigsetjmp(...) != 0) {
// Error handling code
printf("%d", var); // could print 2, 3 or even "potato". Local vars get trashed.
}
// code that might call siglongjmp to bail out to Error handling code
所以在*setjmp
之后,您真的想做所有有趣的事情
int var = 3;
if (sigsetjmp(...) != 0) {
// Error handling code
var = 2;
printf("%d", var); // now you know it's 2
}
// code that might call siglongjmp to bail out to Error handling code
要想让它在*longjmp
中存活下来,需要将其标记为volatile
volatile int var = 3;
var = 2;
if (sigsetjmp(...) != 0) {
// Error handling code
printf("%d", var); // probably 2
}
// code that might call siglongjmp to bail out to Error handling code
即使这样也可能不够。它可能需要被称为sigu或类似的东西。但是尽量不要需要像那样疯狂的东西
int var = 3;
memcpy(var, (int *){2}); //memcpy is pretty reliable (C99ism: immediate pointer))
if (sigsetjmp(...) != 0) {
// Error handling code
printf("%d", var); // probably 2
}
// code that might call siglongjmp to bail out to Error handling code
请不要使用
setjmp
等,也不要使信号处理程序复杂化。有更好的机制。请说明需要什么。这些函数不会恢复静态/全局变量的值。@EdHeal:实际上几乎所有“更好的机制”都有无法解决的竞争条件。如果您确实想使用报警
可靠地中断一个操作(并且只有在被中断的操作是异步信号安全的情况下才合法),某种形式的longjmp
是您唯一的选择。@R.我不同意。信号不受控制。使信号处理程序更简单。在黑板上做一个标记,然后流程可以定期检查该标记是否存在。至少流程会知道ir在其思路中的位置。@Potatoswatter-为什么有这么多双重否定-你的论点没有任何意义。是的,我确实在调用siglongjmp之前调用了sigsetjmp。超时后,调用siglongjmp为call,会触发sigsetjmp return 1,错误代码为call。但是调用“(*pt2Object.*fpt)(“sigsetjmp之后的timeouted”);”不再起作用。你能给我解释一下吗?不,你不能。一旦设置了信号处理程序,siglongjmp
就有可能被调用,但是您还没有调用sigsetjmp
。他指的是第二个调用,在“处理程序”中@khanhhh89您偏离了我展示的伪代码。它必须遵循这种形式。@khanhhh89 R所说的是,您依赖报警超时来延迟信号处理程序。最好在sigsetjmp
@Potatoswatter Yes之后再设置警报。很好的说法。