如何以编程方式告诉我们,如果两个变量是同一堆栈上? (在Windows中)
-
20-09-2019 - |
题
我在一个线程。我有一个地址。是从相同的堆栈上的变量,我使用的地址?
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堆栈(S)成长为必要的,但我也知道,有以生长的限制,并在每一个函数调用(在调试至少)有堆栈溢出检测代码。所以我觉得这是可以做到。
现在,我也知道,我可以/应该使用线程ID等,但我想在这里实现一些棘手的无锁编码,我真的没有房间存放线程ID,只是一个指针。 (我希望能避免CMPXCH16)。请相信我,我有点知道我在做什么: - )
。这是Windows的只有现在。但更轻便越好。 (NT / XP / 7 / CE?)
P.S。这个网站被称为“计算器”,所以它应该是问正确的地方,不应该吗? : - )
编辑:添加上下文中,由于每个人在问。 我实现一个类似于调用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
}
(嗯,我能想到了很多办法,但不知道大画面,它们可能都是完全错误的......)