2

私はスレッドにいます。住所があります。そのアドレスは、私が使用しているのと同じスタック上の変数からのものですか?

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などを使用できる/使用すべきであることも知っています. (CMPXCH16を避けたいと思っています)。私が何をしているのかをある程度知っていることを信じてください:-)。

これは、現時点では Windows 専用です。しかし、携帯性が高いほど良いです。(NT/XP/7/CE?)

PSこのサイトは「stackoverflow」と呼ばれているので、質問するのに適切な場所であるはずですよね? :-)

編集:誰もが尋ねているので、コンテキストを追加します。pthread_once または boost.threads call_once に似たカスタム call_once を実装しています。私は再帰をチェックしようとしています。私が取り組まなければならないことは非常に限られています。関数パラメーターを追加できません。プログラムの残りの部分が何をしているのか、たとえばどれだけの TLS が既に使用されているかを推測することはできません。などなど。私は自分の 1 つの関数内でしかコーディングできず、それ以外のことについて変更や仮定を行うことはできません。

質問/回答ありがとうございます。

4

3 に答える 3

2

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;
}
于 2009-11-17T08:39:51.387 に答える
2

(テストされていない)のようなクレイジーなものはどうですか:

declspec(__thread) void* stackBottom;

void Thread1Routine(void* arg)
{
  volatile int bottom;
  stackBottom = &bottom;

  ... (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);
}

(理論的なレジスタベースの引数の受け渡しの問題を削除するために編集されました)

于 2009-11-16T17:18:52.403 に答える
1

から呼び出されたときに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
}

(まあ、いろいろ考えられるけど、全体像が分からないと、全部間違ってるかも…)

于 2009-11-16T17:21:53.457 に答える