[英]How to programmatically tell if two variables are on the same stack? (in Windows)
我有一个话题。 我有一个地址。 该地址是否来自我正在使用的同一堆栈中的变量?
static int *address;
void A()
{
int x;
atomic::CAS(address, 0, &x); // ie address = &x
// ...
}
void B()
{
int y;
int * addr = atomic::read(address); // ie addr = address
if (addr && on_same_stack(&y, addr))
{
// B() called from A()
}
else
{
// B() called from different thread than A()
}
}
我需要实现on_same_stack(addr1, addr2)
。 我知道Windows上的堆栈会根据需要增长,但是我也知道增长是有限制的,并且(至少在调试中)每个函数调用上都有堆栈溢出检查代码。 所以我认为可以做到。
现在,我也知道我可以/应该使用线程ID,等等。但是我试图在这里实现一些棘手的无锁编码,而且我实际上没有足够的空间来存储线程ID,只有一个指针。 (我希望避免使用CMPXCH16)。 请相信我,我有点知道我在做什么:-)。
目前仅适用于Windows。 但是,便携性越好。 (NT / XP / 7 / CE?)
PS此站点称为“ stackoverflow”,因此应该在正确的位置提问,不是吗? :-)
编辑:添加上下文,因为每个人都在问。 我正在实现类似于pthread_once或boost.threads call_once的自定义call_once。 我正在尝试检查递归。 我的工作非常有限。 我无法添加函数参数。 我无法对程序的其余部分进行假设,例如它们已经使用了多少TLS。 等等,我只能在我的一个函数内编写代码,而对该函数之外的任何内容均不做任何更改或假设。
感谢您的问题/答案。
疯狂的东西(未经测试)怎么样:
declspec(__thread) void* stackBottom;
void Thread1Routine(void* arg)
{
volatile int bottom;
stackBottom = ⊥
... (do stuff which ends up calling on_same_stack()) ...
}
bool on_same_stack(void* p)
{
volatile int top;
return ((LONG_PTR)p >= (LONG_PTR)&top) && ((LONG_PTR)p <= (LONG_PTR)stackBottom);
}
(已编辑,可消除理论上基于寄存器的arg传递问题)
这些示例使用主线程,但实际上它必须可以在任何线程中使用。
范例1:
#include <iostream>
#include <windows.h>
#include <winnt.h>
#include <intrin.h>
inline size_t get_thread_top_stack_size()
{
NT_TIB *s = (NT_TIB*)getTib();
return (size_t)s->StackBase ;
}
int global_var;
int main ()
{
size_t sp_value = 0;
_asm { mov [sp_value], esp }
size_t thread_top_stack = get_thread_top_stack_size();
int my_local_var;
size_t my_local_var_addr = (size_t)&my_local_var;
if (my_local_var_addr < thread_top_stack && my_local_var_addr > sp_value ) {
std::cout << "Yes, on the thread stack";
} else {
std::cout << "No, not on the thread stack";
}
size_t my_global_var_addr = (size_t)&global_var;
if (my_global_var_addr < thread_top_stack && my_global_var_addr> sp_value ) {
std::cout << "Yes, on the thread stack";
} else {
std::cout << "No, not on the thread stack";
}
return 0;
}
范例2:
#include <windows.h>
#include <winnt.h>
#include <intrin.h>
inline NT_TIB* getTib()
{
return (NT_TIB*)__readfsdword( 0x18 );
}
inline bool is_var_on_the_thread_stack(void* ptr)
{
NT_TIB *nt_tib = getTib();
return (nt_tib->StackBase >= ptr) && (nt_tib->StackLimit <= ptr );
}
int my_global_var;
int main ()
{
int my_thread_var;
if (is_var_on_the_thread_stack(&my_thread_var)) {
std::cout << "Yes, on the thread stack" << std::endl;
} else {
std::cout << "No, not on the thread stack" << std::endl;
}
if (is_var_on_the_thread_stack(&my_global_var)) {
std::cout << "Yes, on the thread stack" << std::endl;
} else {
std::cout << "No, not on the thread stack" << std::endl;
}
return 0;
}
从您的注释B() called from A()
,您不能只是将参数传递给B()
并从A()
调用时将其设置为特定值吗? (使用默认参数值,不需要做大改动)
您的样本不是很完整,因此这是另一种尝试,可以对您的问题做出很多假设 ……怎么办:
void A()
{
B_lockfree();
}
void B()
{
// acquire a lock here
B_lockfree();
// release your lock here
}
void B_lockfree()
{
// do whatever you want here
}
(嗯,我可以想到很多方法,但是在不了解全局的情况下,它们可能完全是错误的……)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.