繁体   English   中英

如何以编程方式判断两个变量是否在同一堆栈上? (在Windows中)

[英]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传递问题)

使用Win32线程信息块

这些示例使用主线程,但实际上它必须可以在任何线程中使用。

范例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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM