Как программно определить, находятся ли две переменные в одном стеке?(в Windows)

StackOverflow https://stackoverflow.com/questions/1743511

Вопрос

Я нахожусь в затруднительном положении.У меня есть адрес.Является ли этот адрес переменной из того же стека, который я использую?

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 растет по мере необходимости, но я также знаю, что существует предел росту и что (по крайней мере, в debug) при каждом вызове функции выполняется код проверки переполнения стека.Так что я думаю, что это можно сделать.

Теперь я также знаю, что я мог бы / должен использовать идентификаторы потоков и т.д.Но я пытаюсь реализовать здесь какое-то хитрое кодирование без блокировок, и у меня действительно нет места для хранения идентификаторов потоков, только один указатель.(Я надеюсь избежать CMPXCH16).Пожалуйста, поверьте мне, что я в какой-то степени знаю, что делаю :-).

Пока это только для Windows.Но чем портативнее, тем лучше.(NT/XP/7/CE?)

P.S.этот сайт называется "stackoverflow", так что это должно быть подходящее место для вопроса, не так ли?:-)

Редактировать:добавляем контекст, поскольку все спрашивают.Я реализую пользовательский call_once, похожий на pthread_once или boost.threads 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);
}

(отредактировано, чтобы устранить теоретические проблемы с передачей аргументов на основе регистров)

Другие советы

Используя Информационный блок потока 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 с атрибуция
Не связан с StackOverflow
scroll top