2012-04-12 188 views
38

新しいC++には、このstd :: thread型があります。魅力のように動作します。 ここでは、より簡単なデバッグのために各スレッドに名前を付けたいと思います(javaのように)。std :: thread - スレッドのネーミング

pthread_setname_np(pthread_self(), "thread_name"); 

が、どのように私はCでこれを行うことができ++ 0xの:私はどうなるのpthreadで ? 私はそれがLinuxシステムの下でpthreadを使用していることを知っていますが、私は自分のアプリケーションを移植可能にしたいと思います。まったく可能ですか?

+1

Windowsでは、スレッド名はデバッガのプロパティです(つまり、アプリケーション自体の外部で追跡されます)。結果として、 'pthread_getname_np' – MSalters

答えて

26

これを行うための移植可能な方法は、thread::get_id()から得られたスレッドのIDをキーとする名前のマップを維持することです。また、スレッド内から名前にアクセスする必要がある場合は、コメントに示唆されているように、thread_local変数を使用することもできます。

移植性が必要ない場合は、基礎となるpthread_tthread::native_handle()から取得し、好きなプラットフォーム固有のすべてのことを行うことができます。スレッド命名関数の_npは "not posix"を意味するので、すべてのpthread実装で使用可能であるとは限りません。

+2

「スレッドのIDでキー付けされた名前のマップ」またはスレッドローカル記憶域と同等のものはありません。もちろん、あなたがやっているデバッグは、あなたが知りたいスレッドの内部からだけであると仮定します。 –

+1

このアイデアを包括する設計に関しては、アプリケーションでThreadFactoryを使用することを検討したいと思うかもしれません。作成する際にスレッドを登録したり、必要に応じて必要な '#ifdef'プリコンパイラを使用してプラットフォーム固有のコードを選択します。 – Dennis

+7

デバッガがスレッドの名前を表示するので、デバッガが内部的にいくつかの名前のマップを保持することは無意味ですので、デバッグを簡単にするために、名前付けスレッドの全ポイントがあります。 –

9

std::thread::native_handleを使用すると、下位実装の定義済みスレッドを取得できます。そのための標準的な機能はありません。

例はhereです。

3

ウィンドウ[デバッガ]の場合は、「通常の」方法を簡単に使用できます。 http://msdn.microsoft.com/en-gb/library/xcb2z8hs.aspx

ちょうどあなたが

#include <windows.h> 
DWORD ThreadId = ::GetThreadId(static_cast<HANDLE>(mThread.native_handle())); 
+0

これはおそらく動作しますが、一般的なC++ではないため、クロスプラットフォームのソリューションではありません。とにかくそれを提案してくれてありがとう。 –

+2

ああ、それは間違いなくウィンドウだけですが、誰も実際にウィンドウにそれを設定する方法を教えていませんでした。 (それは動作します、私はそれを使用します:) –

15

を通じて多くのLinuxesだけでなく、Windowsに対処するためのラッパーを作るの試みを取得することができ、スレッドIDが必要です。必要に応じて編集してください。

#ifdef _WIN32 
#include <windows.h> 
const DWORD MS_VC_EXCEPTION=0x406D1388; 

#pragma pack(push,8) 
typedef struct tagTHREADNAME_INFO 
{ 
    DWORD dwType; // Must be 0x1000. 
    LPCSTR szName; // Pointer to name (in user addr space). 
    DWORD dwThreadID; // Thread ID (-1=caller thread). 
    DWORD dwFlags; // Reserved for future use, must be zero. 
} THREADNAME_INFO; 
#pragma pack(pop) 


void SetThreadName(uint32_t dwThreadID, const char* threadName) 
{ 

    // DWORD dwThreadID = ::GetThreadId(static_cast<HANDLE>(t.native_handle())); 

    THREADNAME_INFO info; 
    info.dwType = 0x1000; 
    info.szName = threadName; 
    info.dwThreadID = dwThreadID; 
    info.dwFlags = 0; 

    __try 
    { 
     RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); 
    } 
    __except(EXCEPTION_EXECUTE_HANDLER) 
    { 
    } 
} 
void SetThreadName(const char* threadName) 
{ 
    SetThreadName(GetCurrentThreadId(),threadName); 
} 

void SetThreadName(std::thread* thread, const char* threadName) 
{ 
    DWORD threadId = ::GetThreadId(static_cast<HANDLE>(thread->native_handle())); 
    SetThreadName(threadId,threadName); 
} 

#else 
void SetThreadName(std::thread* thread, const char* threadName) 
{ 
    auto handle = thread->native_handle(); 
    pthread_setname_np(handle,threadName); 
} 


#include <sys/prctl.h> 
void SetThreadName(const char* threadName) 
{ 
    prctl(PR_SET_NAME,threadName,0,0,0); 
} 

#endif 
+1

これはWindowsの部分を明確にするためですhttps://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx – BillyT2

+0

Windowsでは、 SetThreadDescription()API:http://stackoverflow.com/a/41446477/434413これは新しいMSツールで使用されている新しい公式APIです(この回答に示されている方法は古い方法ですが、例外がスローされた時点でVisual Studioデバッガ内で実行されているプロセスに対してのみ機能します)。 –

+0

注:RaiseExceptionを含むWindowsコードは、デバッガでリアルタイムにキャッチされます。私。スレッドの開始時にRaiseExceptionを一度発生し、後でデバッガをアタッチすると、スレッド名がわかりません。 – Sergey

2

私は両方(私たちは基本的にはstdすることは非常に類似していた当社独自のThreadクラス::スレッドを発明した場所)と1つの中で、私はかなり最近書い++、11 Cより以前のシステムで行われ、これを見てきました。

基本的に、プールはstd :: thread 2レイヤーを実際に置いています。あなたは、std :: threadと名前、IDなどのメタデータとそのメタデータにリンクするコントロール構造体を含むPoolThreadクラスを持っています。制御プール、およびThreadPool自体です。
1)明示的な「detach」、「join」、std :: thread構築の開始スレッドをすべてユーザーから隠すことができます。これにより、より安全な&クリーナーコードが生成されます。
2)リソース管理の改善:スレッドが多すぎるとパフォーマンスが低下します。適切に構築されたプールは、自動負荷分散やハングまたはデッドロックされたスレッドのクリーンアップなどの高度な処理を実行できます。
3)スレッドの再利用:std :: threadそれ自体は、すべての並列タスクをそれ自身のスレッドで実行することによって最も簡単に使用できます。しかし、スレッドの作成&の破壊は高価であり、注意しないと並列処理から簡単にスピードブーストを行うことができます。そのため、キューから作業タスクを引き出し、何らかの信号を受信した後に終了するだけのプールスレッドを使用する方が一般的です。
4)エラー処理:std :: threadは単なる実行コンテキストです。実行中のタスクが処理されない例外をスローした場合や、std :: thread ITSELFが失敗した場合、プロセスはただちにクラッシュします。フォールトトレラントなマルチスレッディングを行うには、プールなどが必要です。このようなことをすばやくキャッチして、少なくともプロセスが終了する前に意味のあるエラーメッセージを出すようにしてください。

+4

ポイント2について:ハングしたスレッドまたはデッドロックされたスレッドをクリーンアップするためにプログラムにロジックを追加すると、単にバグを隠そうとしているだけです。代わりにバグを修正することをお勧めします。何か似たようなことがポイント4に当てはまります。スレッドのトップレベルに未処理の例外がある場合、コードに致命的なバグがあります。ここでも、優先順位はバグを修正することであり、状況を「正常に」処理することではありません。 – cmaster