新しいC++には、このstd :: threadタイプがあります。魔法のように機能します。ここで、デバッグをより簡単にするために各スレッドに名前を付けたいと思います(Javaを使用すると可能です)。pthreadを使用すると、次のようになります。
pthread_setname_np(pthread_self(), "thread_name");
しかし、どうすればC++ 0xでこれを行うことができますか? Linuxシステムの下位でpthreadを使用していることは知っていますが、アプリケーションを移植可能にしたいと思います。まったく可能ですか?
これを行うポータブルな方法は、thread::get_id()
から取得したスレッドのIDをキーとする名前のマップを維持することです。または、コメントで提案されているように、スレッド内からのみ名前にアクセスする必要がある場合は、_thread_local
_変数を使用できます。
移植性が必要ない場合は、thread::native_handle()
から基になる_pthread_t
_を取得し、それを使用してプラットフォーム固有の任意の方法を実行できます。スレッド命名関数の__np
_は「posixではない」ことを意味するため、すべてのpthread実装で使用できることが保証されているわけではないことに注意してください。
多くのLinuxとWindowsを扱うラッパーを作成する試み。必要に応じて編集してください。
#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
std::thread::native_handle
を使用して、基になる実装定義のスレッドを取得できます。そのための標準機能はネイティブにありません。
例を見つけることができます here 。
Windows [デバッガ]の場合、「通常の」メソッドを簡単に使用できます。 http://msdn.Microsoft.com/en-gb/library/xcb2z8hs.aspx
経由で取得できるスレッドIDが必要です
#include <windows.h>
DWORD ThreadId = ::GetThreadId( static_cast<HANDLE>( mThread.native_handle() ) );
私は両方とも、c ++ 11(std :: threadと非常によく似た独自のThreadクラスを基本的に発明した)より前のシステムで行われたのを見て、かなり最近書いたもので見ました。
基本的に、プールはstd :: thread 2層を実際に配置します。std:: threadに加えて、名前、IDなどのメタデータ、およびそれを制御プールにリンクする制御構造を含むPoolThreadクラスがあります。 ThreadPool自体。いくつかの理由により、ほとんどのスレッドコードでスレッドプールを使用する必要があります。
1)すべての明示的な「切り離し」、「結合」、std :: thread構築のスレッドの開始などをユーザーから隠すことができます。これにより、より安全でクリーンなコードが生成されます。
2)リソース管理の改善:スレッドが多すぎると、少なすぎるよりもパフォーマンスが低下します。うまく構築されたプールは、自動負荷分散やハングまたはデッドロック状態のスレッドのクリーンアップなどの高度な処理を実行できます。
3)スレッドの再利用:std :: thread自体は、すべての並列タスクを独自のスレッドで実行することにより、最も簡単に使用できます。ただし、スレッドの作成と破棄は高価であり、注意しないと、並列処理の速度向上を簡単に圧倒する可能性があります。そのため、通常、作業タスクをキューからプルし、何らかのシグナルを受信した後にのみ終了するプールスレッドを使用する方が理にかなっています。
4)エラー処理:std :: threadは単なる実行コンテキストです。実行中のタスクが未処理の例外をスローするか、std :: thread ITSELFが失敗すると、プロセスはすぐにクラッシュします。フォールトトレラントマルチスレッドを実行するには、そのようなものをすばやくキャッチし、少なくともプロセスが終了する前に意味のあるエラーメッセージを出力できるPoolまたは類似のものが必要です。