c ++ 11で整数スレッドIDを取得する方法


84

c ++ 11には現在のスレッドIDを取得する可能性がありますが、整数型にキャストすることはできません。

cout<<std::this_thread::get_id()<<endl;

出力:139918771783456

cout<<(uint64_t)std::this_thread::get_id()<<endl;

エラー:タイプ 'std :: thread :: id'からタイプ 'uint64_t'への無効なキャスト他のタイプと同じ:タイプ 'std :: thread :: id'からタイプ 'uint32_t'への無効なキャスト

整数のスレッドIDを取得するためにポインターキャストを実行したくありません。それを行うための合理的な方法(ポータブルにしたいので標準)はありますか?


13
何のために整数にする必要がありますか?その上でいかなる種類の算術演算も実行する意味がないことが保証されており、プロセスのコンテキスト外では意味がないため、デバッグ以外にシリアル化する必要はありません(operator<<正常に処理されるようです)。
–hmakholmは2011

4
このようなもの:1024cores.net/home/lock-free-algorithms/false-sharing --- falseですが、N = MAX_THREAD_COUNTの代わりにN = 128のようなものを使用し、thread_id%Nを実行します
NoSenseEtAl 2011

9
本当にポータブルにしたい場合thread::idは、整数としてまったく表されない可能性に備える必要があります。リンク先のページは、スレッドIDでインデックス付けされた配列を使用します。map<thread::id, int>代わりに使用することを検討しましたか?次にid、変換を行わずに、クラスに対してすでに定義されている関係演算子を使用できます。標準ではhash<thread::id>、も定義されているため、順序付けされていないコンテナも使用できます。
ロブ・ケネディ

3
@Robそのマップにはミューテックスが必要です:(
NoSenseEtAl 2011

1
@SwissFrankまたはCHF:PIはまだ存在していると言えますが、受け入れられた答えは私にとっては問題ないと思います。プログラムの期間中、変数ID値が一意であることを確認するのは私次第です。
NoSenseEtAl

回答:


33

移植可能な解決策は、独自に生成したIDをスレッドに渡すことです。

int id = 0;
for(auto& work_item : all_work) {
    std::async(std::launch::async, [id,&work_item]{ work_item(id); });
    ++id;
}

このstd::thread::id型は、算術演算ではなく、比較にのみ使用されます(つまり、缶に記載されているように:識別子)。生成しても、そのテキスト表現は、operator<<ある指定されていないので、あなたはそれが多数の表現であることに頼ることはできません。

std::thread::idIDを直接渡す代わりに、値のマップを使用して独自のIDを作成し、このマップを(適切に同期して)スレッド間で共有することもできます。


1
あはは!しかし、テキスト表現あります!それは人間が視覚的にそれらの間の区別を見つけるのに十分ですよね?
xunie 2016

ここで説明するthread :: id(またはthis_thread :: get_id())ソリューションは、プログラマー固有ではないため、最適です。文字列または整数表現を取得するには、以下のマイクの文字列ストリームの回答を参照してください。
アンドリュー

@Andrew私は答えの中で、「operator <<によって生成されたテキスト表現でさえ指定されていないので、それが数値の表現であると信頼することはできません」と述べました。「最高」という言葉の怪しげな定義が手元にあるようです。
R. Martinho Fernandes

「最良」は文字列表現とは関係ありませんでした。
アンドリュー

1
また、私はちょうど10,000,000私自身のための反復としてベンチマークをしたthis_thread :: GET_ID()邪悪速いです:pastebin.com/eLa3rKQEデバッグモードは、コールごとに0.0000002543827秒かかり、リリースは私のために呼び出しごとに0.00000003652367秒かかります。(Intel i5 2.60 GHz)
Andrew

85

あなたはただする必要があります

std::hash<std::thread::id>{}(std::this_thread::get_id())

を取得しsize_tます。

cppreferenceから:

クラスのテンプレート特殊化によりstd::hashstd::thread::idユーザーはスレッドの識別子のハッシュを取得できます。


35
これは必要だと思いますstd::hash<std::thread::id>()(std::this_thread::get_id())ね。
バリー

12
ハッシュは一意であることが保証されますか?おそらくそうではなく、一意のスレッド識別子としての使用を無効にします。
Michael Goldshteyn 2013

2
与えられた例は、少なくともClang3.4とlibstdc ++ 4.8では機能しません。ただし、バリーの再定式化は機能します。
Arto Bendiken 2014年

3
答えてくれてありがとう888。MSコンパイラにはthread :: id :: hash()がありますが、Barryのコードは標準に準拠しています。ハッシュは衝突する可能性があります。スレッドごとにハッシュを設定することはまだ便利です(衝突確率が0に近いことを願っています)
a.lasram 2015年

1
この場合、MSVCは実際にはハッシュされたスレッドIDを返します。あなたにも、あなた自身の...生成される可能性があります
rustyx

25

別のID(アイデア?^^)は、文字列ストリームを使用することです。

std::stringstream ss;
ss << std::this_thread::get_id();
uint64_t id = std::stoull(ss.str());

また、問題が発生した場合に例外が発生したくない場合は、trycatchを使用してください...


2
いい答えだ。これは一般的な目的に役立ちます。
iammilind 2014

5
std::thread::idスレッドIDが内部的に整数で表されることが保証されていないのとほぼ同じ方法で、整数を構成する文字として出力される保証がないため、これは移植性がありません。
blubberdiblub 2017年

1
@Nikosは、実装が整数が不十分であると選択したときはいつでも。または、他の理由で不適切と見なされる場合はいつでも。ここでのポイントは、仕様で整数として指定されていない場合(そして、指定されていない場合は、より抽象的な保証があるだけです)、どの実装でも整数であることに依存することはできず、信頼すべきではありません。std::thread::id整数の代わりに型として使用するだけで、それが存在します。また、文字列表現を数字を構成する数字として再解釈しないでください。不透明またはデバッグ/ロギング出力として扱います。
blubberdiblub

6

1つのアイデアは、スレッドローカルストレージを使用して変数を格納することです(スレッドローカルストレージのルールに準拠している限り、どのタイプでもかまいません)。次に、その変数のアドレスを「スレッドID」として使用します。明らかに、算術演算は意味がありませんが、整数型になります。

後世のために: pthread_self()apid_tを返し、posixです。これは、ポータブルの定義としてはポータブルです。

gettid()、ほぼ確実に移植性はありませんが、GDBに適した値を返します。


pthread_self()実際には、pthread_t不透明なを返します(これは、プラットフォーム固有ですが、少なくとも明らかに整数であるpid_t(によって返されるgettid())とは異なります)。しかし、最初のビットは+1で、問題は解決しました。
キャメロン

4

私はこれがどれほど速いか本当にわかりませんが、これは私が何とか推測した解決策です:

const size_t N_MUTEXES=128;//UINT_MAX,not 128  for answer to my original question
hash<std::thread::id> h;
cout<<h(std::this_thread::get_id())%N_MUTEXES<<endl;

繰り返しますが、構造体へのポインターを取得し、それをunsigned intまたはuint64_tにキャストすることが答えだと思い始めています...編集:

uint64_t get_thread_id()
{
    static_assert(sizeof(std::thread::id)==sizeof(uint64_t),"this function only works if size of thead::id is equal to the size of uint_64");
    auto id=std::this_thread::get_id();
    uint64_t* ptr=(uint64_t*) &id;
    return (*ptr);
}
int main()
{
    cout<<std::this_thread::get_id()<<"  "<<get_thread_id()<<endl;
}

地獄のような問題を防ぐためのstatic_assert :)この種のバグを探すのに比べて、書き換えは簡単です。:)


3
hash関数で重複した値を取得しないという保証はありません。%それを実行した場合はなおさらです
R.マルティーニ・フェルナンデス

1
あなたはstd::this_thread::get_id()!でその保証を得ることができません。しかし、おそらくそれは必要ありません。互いに共有しているいくつかのスレッドは、他のすべてのスレッドと共有しているすべてのスレッドと同じ大きな問題を引き起こしません。のようなものconst size_t N_COUNTERS = 128; struct Counter { std::atomic<int> counter; char pad[CACHE_LINE_SIZE - sizeof(atomic<int>); } counters[N_COUNTERS];はおそらく大丈夫です。(非常に軽量な同期のためのアトミックまたはスピンロック。)
Scott Lamb

@R。Martinho Fernandes私が言ったように、私はint値に興味があるので、それを%できます。衝突は、基本的にスコットが言ったように、まれであれば問題ありません。
NoSenseEtAl 2011

1
私は実際にこれを試しましたが、完全に間違っていました。atomic<int>代わりに使用するだけでintは、競合がなくても劇的な速度低下になります。
スコットラム

1
static_assertをこのideone.com/Q7Nh4のようなものに置き換えることができます(代わりに、正確なサイズ要件を適用するために簡単に調整できます)。より移植性が高くなります(たとえば、ideoneのスレッドIDが32ビットであることに注意してください)。 。
R.マルティーニ・フェルナンデス

4

thread::native_handle()を返しますthread::native_handle_type。これは、へのtypedeflong unsigned intです。

スレッドがデフォルトで構築されている場合、native_handle()は0を返します。それに接続されているOSスレッドがある場合、戻り値はゼロ以外です(POSIXではpthread_tです)。


std::thread::native_handle_typetypedefはどこに指定されていますlong unsignedか?30.3.1 / 1では、私たちが見ることができるのはtypedef implementation-defined native_handle_type; // See 30.2.3
Ruslan

タイプを発見するためのばかげているが簡単な方法は、thread :: native_handle()をuint8_tなどに割り当てて、意図的なコンパイルエラーを生成することです。次に、コンパイラは型の不一致について文句を言い、型が何であるかを教えてくれます。
Alexey Polonsky 2018

1
それは特定の実装に依存しているので、それは移植性がありません。
ルスラン

まあ、少なくとも基礎となる実装がPOSIX pthreadを使用している場合、native_handle()はpthread_tでなければならないようです。現在、pthread_tはポインター型です(typedef struct pthread * pthread_t)。したがって、std :: thread :: native_handle_typeがポインタ(たとえば、size_tまたはunsigned long)を含むことができる整数型であることは理にかなっています。
Alexey Polonsky 2018

3

このように、動作するはずです:

std::stringstream ss;
ss << std::this_thread::get_id();
int id = std::stoi(ss.str());

ライブラリsstreamを含めることを忘れないでください


いいですが、なぜそれが整数だと思いますか?それは16進数または他のものにすることができます。
rustyx 2017年

を使用している場合はstd::stringstream、それを使用しoperator >>てintに変換できます。が不可欠であると確信している場合uint64_tではidなく、タイプとして実際に好むでしょう。intid
aniliitb 1019

3

thread :: get_id()を使用しない主な理由は、それが単一のプログラム/プロセス内で一意ではないことです。これは、最初のスレッドが終了すると、IDを2番目のスレッドで再利用できるためです。

これは恐ろしい機能のように見えますが、c ++ 11ではどうでしょうか。


2

これは、thread_idを何に使用するかによって異なります。使用できます:

std::stringstream ss;
ss << std::this_thread::get_id();
uint64_t id = std::stoull(ss.str());

これにより、処理時に一意のIDが生成されます。ただし、制限があります。同じプロセスの複数のインスタンスを起動し、それぞれがスレッドIDを共通のファイルに書き込む場合、thread_idの一意性は保証されません。実際、重複する可能性が非常に高くなります。この場合、次のようなことができます。

#include <sys/time.h>
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
uint64_t id = (ts.tv_sec % 1000000000) * 1000000000 + ts.tv_nsec;

これで、システム全体で一意のスレッドIDが保証されます。


オーバーロードされたものは何でも出力operator<<できますが、常に整数を出力すると想定するのは誤りです。
rustyx 2017年

2

別の選択肢:

#include <atomic>

static std::atomic<unsigned long long> thread_counter;

unsigned long long thread_id() {
    thread_local unsigned long long tid = ++thread_counter;
    return tid;
}

x8664ビットでg ++によって生成されたこの関数のコードは、次のとおりです。

_Z9thread_idv:
        cmp     BYTE PTR fs:_ZGVZ9thread_idvE3tid@tpoff, 0
        je      .L2
        mov     rax, QWORD PTR fs:_ZZ9thread_idvE3tid@tpoff
        ret
.L2:
        mov     eax, 1
        lock xadd       QWORD PTR _ZL14thread_counter[rip], rax
        mov     BYTE PTR fs:_ZGVZ9thread_idvE3tid@tpoff, 1
        mov     QWORD PTR fs:_ZZ9thread_idvE3tid@tpoff, rax
        ret
_ZGVZ9thread_idvE3tid:
        .zero   8
_ZZ9thread_idvE3tid:
        .zero   8

つまり、関数を初めて呼び出すときを除いて、正しく予測される同期のない単一のブランチです。その後、同期なしの単一のメモリアクセス。


@NoSenseEtAl:あなたの質問を理解できません...thread_localすでにの保存期間について説明していますtidstatic以下のためのthread_counterあなたは、このコンパイル単位の外にそれを公開したくないからです。
6502

この種の奇妙なことに、スレッドIDを照会する順序でスレッドIDが割り当てられます。(私は自分自身と非常によく似た何かをしたことがあり、この奇妙さは好きではありませんでした。)また、通常ではないゼロから割り当てます。(たとえば、GDBは1から始まるスレッドIDを報告します。)
スイスフラン

1
@SwissFrank:これは単なる数値であり、返される値を読みすぎないでください。クエリを実行したときに割り当てられたことを知る法的な方法はありません:-)。0有効なIDであるという事実については、良い点であり、代わりにプリインクリメントを使用して修正できます。そのために答えを変更します。
65024

1

たぶん、この解決策は誰かに役立つでしょう。初めてimと呼んでくださいmain()。警告:names無期限に成長します。

std::string currentThreadName(){
    static std::unordered_map<std::thread::id,std::string> names;
    static std::mutex mtx;

    std::unique_lock<std::mutex> lock(mtx);

    auto id = std::this_thread::get_id();

    if(names.empty()){
        names[id] = "Thread-main";
    } else if(names.find(id) == names.end()){
        std::stringstream stream;
        stream << "Thread-" << names.size();
        names[id] = stream.str();
    }

    return names[id];
}

それは遅い、使用STDである、にstringstreamを使用していない:: TO_STRING
NoSenseEtAl
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.