如何在c ++ 11中获取整数线程id

NoS*_*tAl 76 c++ multithreading c++11

c ++ 11有可能获得当前的线程ID,但它不能转换为整数类型:

cout<<std::this_thread::get_id()<<endl;
Run Code Online (Sandbox Code Playgroud)

输出:139918771783456

cout<<(uint64_t)std::this_thread::get_id()<<endl;
Run Code Online (Sandbox Code Playgroud)

错误:从类型'std :: thread :: id'到类型'uint64_t'的无效强制转换与其他类型相同:从类型'std :: thread :: id'到类型'uint32_t'的无效强制转换

我真的不想做指针转换来获取整数线程ID.是否有一些合理的方法(标准因为我希望它是便携式的)来做到这一点?

888*_*888 74

你只需要这样做

std::hash<std::thread::id>{}(std::this_thread::get_id())
Run Code Online (Sandbox Code Playgroud)

得到一个size_t.

cppreference:

的模板专门std::hashstd::thread::id类允许用户获得线程的标识符的哈希值.

  • 我认为这必须是`std :: hash <std :: thread :: id>()(std :: this_thread :: get_id())`,不是吗? (34认同)
  • 哈希是否会保证唯一?可能不会,将其用作唯一的线程标识符. (12认同)
  • 感谢888的答案.MS编译器确实有thread :: id :: hash()但Barry的代码符合标准.哈希可以碰撞.每个线程都有一个哈希值(希望碰撞概率接近0) (3认同)
  • 给出的示例至少不适用于Clang 3.4和libstdc ++ 4.8.然而,巴里的重新制定确实有效. (2认同)

R. *_*des 29

可移植的解决方案是将您自己生成的ID传递给线程.

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

std::thread::id类型仅用于比较,而不是用于算术(即,如在can上所述:标识符).通过生产甚至它的文本表示operator<<未指定的,所以你不能依赖于它是一个数字的表示.

您还可以使用std::thread::id值映射到您自己的id,并在线程之间共享此映射(具有适当的同步),而不是直接传递id.

  • 另外,我只是为了自己的缘故进行了 10,000,000 次迭代的基准测试, this_thread::get_id() 速度非常快:http://pastebin.com/eLa3rKQE 调试模式每次调用需要 0.0000002543827 秒,发布模式每次调用需要 0.00000003652367 秒。(英特尔 i5 2.60 GHz) (2认同)

小智 22

另一个id(想法?^^)将使用stringstreams:

std::stringstream ss;
ss << std::this_thread::get_id();
uint64_t id = std::stoull(ss.str());
Run Code Online (Sandbox Code Playgroud)

如果您在出现问题时不想要例外,请使用try catch ...

  • 这是不可移植的,因为不能保证`std :: thread :: id`作为构成整数的字符打印,就像不能保证线程id在内部用整数表示一样. (5认同)
  • 好答案。这将达到一般目的。 (2认同)

tgo*_*art 6

一个想法是使用线程本地存储来存储变量 - 无论什么类型,只要它符合线程本地存储的规则 - 然后使用该变量的地址作为"线程ID".显然任何arithemetic都没有意义,但它将是一个完整的类型.

对于后代: pthread_self()返回a pid_t并且是posix.对于便携式的某些定义,这是便携式的.

gettid(),几乎肯定不是便携式的,但它确实返回了GDB友好的价值.


Fed*_*zzo 6

这样,应该可以工作:

std::stringstream ss;
ss << std::this_thread::get_id();
int id = std::stoi(ss.str());
Run Code Online (Sandbox Code Playgroud)

请记住包含库流


650*_*502 6

另一种选择:

#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;
}
Run Code Online (Sandbox Code Playgroud)

g++ 在 x86 64 位中为此函数生成的代码如下:

_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
Run Code Online (Sandbox Code Playgroud)

即,没有任何同步的单个分支将被正确预测,除非您第一次调用该函数。之后只需一次内存访问而无需同步。


NoS*_*tAl 5

我真的不知道这有多快,但这是我设法猜测的解决方案:

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;
Run Code Online (Sandbox Code Playgroud)

我再次开始认为获取指向结构的指针并将其转换为 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;
}
Run Code Online (Sandbox Code Playgroud)

static_assert 以防止出现地狱般的问题 :) 与寻找此类错误相比,重写更容易。:)

  • 你不能保证你不会用 `hash` 函数得到重复的值,*如果你 % it 就更少*。 (3认同)

Ale*_*sky 5

thread::native_handle()returns thread::native_handle_type,它是 的 typedef long unsigned int

如果线程是默认构造的,则native_handle()返回0。如果有一个操作系统线程附加到它,则返回值非零(POSIX上是pthread_t)。


mid*_*jji 5

不使用 thread::get_id() 的一个关键原因是它在单个程序/进程中不是唯一的。这是因为一旦第一个线程完成,该 id 可以重用于第二个线程。

这似乎是一个可怕的功能,但它在 c++11 中是什么。