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

发布于 2024-12-04 21:31:33 字数 401 浏览 3 评论 0原文

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。有没有一些合理的方法(标准,因为我希望它是便携式的)来做到这一点?

c++11 has a possibility of getting current thread id, but it is not castable to integer type:

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

output : 139918771783456

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

error: invalid cast from type ‘std::thread::id’ to type ‘uint64_t’
same for other types:
invalid cast from type ‘std::thread::id’ to type ‘uint32_t’

I really dont want to do pointer casting to get the integer thread id. Is there some reasonable way(standard because I want it to be portable) to do it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

层林尽染 2024-12-11 21:31:33

您只需要

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

获取 size_t 即可。

来自 cppreference

针对 std::thread::id 类的 std::hash 模板特化允许用户获取线程标识符的哈希值。

You just need to do

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

to get a size_t.

From cppreference:

The template specialization of std::hash for the std::thread::id class allows users to obtain hashes of the identifiers of threads.

寄居人 2024-12-11 21:31:33

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

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

如果你不想在出现问题时出现异常,请使用try catch......

Another id (idea? ^^) would be to use stringstreams:

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

And use try catch if you don't want an exception in the case things go wrong...

千紇 2024-12-11 21:31: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::id 值到您自己的 id 的映射,并在线程之间共享此映射(通过适当的同步),而不是直接传递 id。

The portable solution is to pass your own generated IDs into the thread.

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

The std::thread::id type is to be used for comparisons only, not for arithmetic (i.e. as it says on the can: an identifier). Even its text representation produced by operator<< is unspecified, so you can't rely on it being the representation of a number.

You could also use a map of std::thread::id values to your own id, and share this map (with proper synchronization) among the threads, instead of passing the id directly.

2024-12-11 21:31:33

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

对于后代:
pthread_self() 返回一个 pid_t 并且是 posix。对于便携式的某些定义来说,这是便携式的。

gettid(),几乎肯定不可移植,但它确实返回一个 GDB 友好的值。

One idea would be to use thread local storage to store a variable - doesn't matter what type, so long as it complies with the rules of thread local storage - then to use the address of that variable as your "thread id". Obviously any arithemetic will not be meaningful, but it will be an integral type.

For posterity:
pthread_self() returns a pid_t and is posix. This is portable for some definition of portable.

gettid(), almost certainly not portable, but it does return a GDB friendly value.

行雁书 2024-12-11 21:31:33

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

这看起来是一个可怕的特性,但它是 c++11 中的。

A key reason not to use thread::get_id() is that it isn't unique for in a single program/process. This is because the id can be reused for a second thread, once the first thread finishes.

This seems like a horrible feature, but its whats in c++11.

霞映澄塘 2024-12-11 21:31:33

这样,应该可以工作:

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

记住包含库 sstream

In this way, should work:

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

Remember to include library sstream

半边脸i 2024-12-11 21:31:33

另一种选择:

#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;
}

x86 64 位中的 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

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

Another alternative:

#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;
}

The generated code for this function by g++ in x86 64-bit is just:

_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

I.e. a single branch without any synchronization that will be correctly predicted except for the first time you call the function. After that just a single memory access without synchronization.

居里长安 2024-12-11 21:31:33

thread::native_handle() 返回 thread::native_handle_type,它是 long unsigned int 的类型定义。

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

thread::native_handle() returns thread::native_handle_type, which is a typedef to long unsigned int.

If thread is default constructed, native_handle() returns 0.
If there is an OS thread attached to it, the return value is non-zero (it is pthread_t on POSIX).

他不在意 2024-12-11 21:31:33

这取决于您想要使用 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。

it depends on what you what you want to use the thread_id for;
you can use:

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

This will generate a unique id withing you process; but there's a limitation: if you launch several instances of the same process and each one of them writes their thread ids to a common file, the uniqueness of the thread_id is not guaranteed; in fact it's very likely you'll have overlaps.
In this case you can do something like:

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

now you are guaranteed unique thread ids systemwide.

離人涙 2024-12-11 21:31:33

也许这个解决方案对某人有帮助。第一次在 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];
}

Maybe this solution be helpful to someone. Call it a first time im main(). Warning: names grows indefinitely.

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];
}
冷月断魂刀 2024-12-11 21:31:33

实际上你也可以通过强制转换来做到这一点:

std::thread::id threadId = std::this_thread::get_id();    
unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<void*>(&threadId));

我比较了 castingstd::hashstd::stringstream 一百万次迭代,发现std::hash最快的解决方案,时间为1293500ns,而转换仅慢 11 毫秒1384200nsstd::stringstream 作为最慢​​,为 351701200ns

You actually can do it with casting too:

std::thread::id threadId = std::this_thread::get_id();    
unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<void*>(&threadId));

I compared casting, std::hash and std::stringstream on a million iterations and found that std::hash is the fastest solution with a time of 1293500ns while casting is only 11ms slower with 1384200ns and std::stringstream as the slowest at 351701200ns.

独享拥抱 2024-12-11 21:31:33

thread::id 只是平台类型的包装器。出于所有意图和目的,它将是一个无符号 32 位整数。因此,继续将其视为无符号 32 位整数。

现在,如果有人正在为某个异国平台编写代码,但情况并非如此,那么当您迁移到新平台时对此进行测试。到目前为止提供的答案与这里实际发生的事情相去甚远,它们让我想挖出我的眼睛。

static_assert(alignof(std::thread::id) == 4, "uh-oh!");
static_assert(sizeof(std::thread::id) == 4, "uh-oh!");

unsigned thread_id() {
  auto id = std::this_thread::get_id();
  return *(unsigned *)&id;
}

我明白为什么他们想让它成为一种独特的类型,但这只是烦人,我们有更好的事情要做,而不是争论这是否符合标准。

thread::id is just a wrapper around the platform type. For all intents and purposes it's is going to be an unsigned 32-bit integer. So go ahead and treat it as an unsigned 32-bit integer.

Now, if someone is writing code for some exotic platform where this is not the case, then test for this as you move to a new platform. The answers provided thus far are so far removed from what's actually going on here that they make me wanna gouge my eyes out.

static_assert(alignof(std::thread::id) == 4, "uh-oh!");
static_assert(sizeof(std::thread::id) == 4, "uh-oh!");

unsigned thread_id() {
  auto id = std::this_thread::get_id();
  return *(unsigned *)&id;
}

I get why they wanted to make it a distinct type but this is just annoying we have better things to do than to argue whether this is in line with the standard or not.

往昔成烟 2024-12-11 21:31:33
namespace std::this_thread
{
    inline _NODISCARD uint32_t get_id_2() noexcept
    {
        thread_local static const auto THIS_THREAD_ID = []()->uint32_t { std::stringstream ss; ss << std::this_thread::get_id(); return std::stoul(ss.str()); }();
        return THIS_THREAD_ID;
    }
}
namespace std::this_thread
{
    inline _NODISCARD uint32_t get_id_2() noexcept
    {
        thread_local static const auto THIS_THREAD_ID = []()->uint32_t { std::stringstream ss; ss << std::this_thread::get_id(); return std::stoul(ss.str()); }();
        return THIS_THREAD_ID;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文