2012-04-03 6 views
0

他のスレッドのレジスタまたはスレッドローカル変数を直接読み取ることはできますか?つまり、カーネルに移動する必要はありませんか?そうする最善の方法は何ですか?他のスレッドのレジスタまたはスレッドローカル変数を読み取る

+0

[ptrace](http://linux.die.net/man/2/ptrace)? –

+0

私は速い解決策を必要とします、ptraceは遅すぎます。そして、ptraceはカーネルに行く必要があります。 – pythonic

+3

なぜこれを行う必要がありますか? –

答えて

1

とにかく便利ではないレジスタを読むことはできません。しかしを読むと、別のスレッドのスレッドローカル変数を簡単に使用することができます。

同期化せずに安全に行うこともできます(ただし、読み取り値はどのような方法でもスレッドに属しません)。シナリオでは、スレッドローカルカウンターなどが表示されます。

具体的にあなたがタグ付けされたとしてx86_64版のLinuxでは、あなたはそのようにそれをすることができます。

// A thread local variable. GCC extension, but since C++11 actually part of C++ 
__thread int some_tl_var; 

// The pointer to thread local. In itself NOT thread local, as it will be 
// read from the outside world. 
struct thread_data { 
    int *psome_tl_var; 
    ... 
}; 

// the function started by pthread_create. THe pointer needs to be initialized 
// here, and NOT when the storage for the objects used by the thread is allocated 
// (otherwise it would point to the thread local of the controlling thread) 
void thread_run(void* pdata) { 
    pdata->psome_tl_var = &some_tl_var; 

    // Now do some work... 
    // ... 
} 

void start_threads() { 
    ... 
    thread_data other_thread_data[NTHREADS]; 
    for (int i=0; i<NTHREADS; ++i) { 
     pthread_create(pthreadid, NULL, thread_run, &other_thread_data[i]);  
    } 

    // Now you can access each some_tl_var as 
    int value = *(other_thread_data[i].psome_tl_var); 
    ... 
} 

は私がワーカースレッドに関するいくつかの統計情報を表示するために同様の使用しました。 C++ではさらに簡単です。スレッドの周りにオブジェクトを作成し、スレッドクラスのフィールドのポインタをローカルのスレッドクラスにし、メンバ関数を使ってアクセスするだけです。

免責事項:これは移植性がありませんが、x86_64、linux、gccで動作し、他のプラットフォームでも動作する可能性があります。

1

カーネルに関係することなくこれを行う方法はありません。実際、何らかの同期を取らずに読み込むことは意味がありません。 ptrace(醜いポータブルではない)を使用したくない場合は、代わりに "私にあなたのレジスタ/ TLSを送る"メッセージに使うリアルタイム信号の1つを選択することができます。大まかな考え方は次のとおりです。

  1. リクエストにグローバルミューテックスをロックします。
  2. グローバル変数のスレッドから、必要なデータ(たとえば、pthread_key_tまたはレジスタを意味する特別な値)に関する情報をスレッドに格納します。
  3. pthread_killでターゲットスレッドに信号します。 (sigactionSA_SIGINFOでインストールされていなければならない)シグナルハンドラで
  4. が要求元に通信するために使用されるグローバル変数にucontext_tことをコピーする(実際ucontext_tを指す)は、信号ハンドラに第void *引数を使用します糸。これにより、すべてのレジスタ値が得られます。 pthread_getspecificは非同期シグナルでは安全でなく、技術的にはこのコンテキストでは動作しないので、TLSはもう少し難しいですが、実際にはうまくいくでしょう。
  5. シグナルハンドラは、要求スレッドに完了したことを示すセマフォ(POSIXによって提供される唯一の非同期シグナル安全同期関数です)をポストして返します。
  6. 要求スレッドは、セマフォを待って終了し、データを読み取り、要求ミューテックスのロックを解除します。

これは(sem_waitおよび多分他)は、少なくとも1つの要求スレッドにkernelspaceする遷移(pthread_kill)を含むことに注意してください、そしてターゲットスレッド1-3シグナルハンドラからの復帰(1、1シグナルハンドラがカーネル空間でまだスリープしていない場合は入力し、可能であればsem_postの場合は1に設定します。それでも、それはおそらく、高速の使用のために設計されていないptraceと混乱するより速いです...

+0

ああ、それは私の目的のために遅いです。私は、これまでにやってきたこと、つまりグローバル配列を使うことにこだわります。 – pythonic

+0

@ user1018562複数のスレッドからアクセスされるグローバル配列は、キャッシュの同期、スヌーピングなどのために、パフォーマンスの低下を招く可能性があります。 – hirschhornsalz

関連する問題