我们正在开发一个新的中断系统(在c ++中),以替换旧的不一致的中断系统。
它的工作原理如下:
希望使其方法可中断的程序员接受BreakFlag
对象作为方法的参数。
在方法期间,程序员检查break_flag.is_set()
,如果是,则退出并整理。
我们希望能够在对程序进行一些更改后,对break_flag.is_set()
的所有原始调用保持相同的顺序。 (我们在一个调用的同一个循环中计算多个调用,因此不同大小的两个操作看起来是相同的)
我们的第一种方法是使用调用堆栈来识别每个实例。例如,在代码中:
void A(BreakFlag& flag) {
flag.is_set();
B(flag);
C(flag);
}
void B(BreakFlag& flag) {
flag.is_set();
C(flag);
}
void C(BreakFlag& flag) {
flag.is_set();
}
每次调用is_set
时我们都会查看调用堆栈,并为此方法生成以下序列:
A
A, B
A, B, C
A, C
然后我们可以使用它来检查每次测试程序时这个序列的检查器,以便有人不能出现并执行此操作:
void A(BreakFlag& flag){ flag.is_set(); B(标志); C(标志); }
void B(BreakFlag& flag) {
flag.is_set();
//C(flag); // I HAVE COMMENTED THIS OUT BECAUSE I DONT LIKE FLAG!
}
void C(BreakFlag& flag) {
flag.is_set();
}
因为它会导致序列:
A
A, B
A, C
哪个与原版不匹配。
我们遇到的问题是,编译器有时会以调用堆栈发生变化的方式进行优化,这会导致我们提出的系统注册错误的失败测试,因为调用堆栈不是它所期望的,即使它是对的。
我们可以通过做类似以下的事情来解决它:
#define CHECK_FLAG(x) actually_check_flag(__LINE__,__FILE__,x)
这将允许我们基本上在代码中ID每个实例。
除此之外,我们无法想出任何方式来识别每个对.is_set
的调用,这些调用不会在光学代码中发生变化,是吗?
答案 0 :(得分:1)
您可以使用RAII手动维护呼叫堆栈。在进入每个函数时构造一个保护对象:
void B(BreakFlag& flag) {
BreakFlagStackGuard guard(flag, "B");
flag.is_set();
C(flag);
}
BreakFlagStackGuard
的构造函数将函数名称"B"
推送到flag.stack
,而析构函数~BreakFlagStackGuard()
(将在B
返回时调用)会弹出它
无论编译器做什么来优化它都需要尊重你的保护对象,这样你就可以保证观察到的调用栈反映了源代码。