标准 C++ 线程 ID - 奇怪的行为

Posted

技术标签:

【中文标题】标准 C++ 线程 ID - 奇怪的行为【英文标题】:Standard C++ Thread IDs - strange behavior 【发布时间】:2013-06-03 14:06:50 【问题描述】:

我需要按需创建一些线程,因为我之前不知道我需要多少。 使用向量std::vector<std::thread> threads;“存储”线程即时消息 每次我创建一个新线程时,我都会将它们推回到向量上:threads.push_back(std::thread(worker));

为了存储(用于测试)线程 ID,我使用以下代码:double test = std::hash<std::thread::id>()(std::this_thread::get_id()); 根据 cpp-references hash、thread::id 和 get_id 这应该可以正常工作。

但只有这一行我得到的 id 总是 0(零)

如果 id 在散列线下方添加以下行,它可以工作,我从线程中得到一个散列 id:std::thread::id tid = std::this_thread::get_id(); 即使我不使用tid

有人可以解释这种行为吗? 我正在使用eclipse juno并多次清理+重建项目......我只是不明白:/

这里是代码: (一行一行,因为这里的格式规则很愚蠢-.-

std::vector<std::thread> threads;
void worker ()
    double test = std::hash<std::thread::id>()(std::this_thread::get_id());
    std::thread::id tid = std::this_thread::get_id();
    printf("%ld\n", test);

void joinThreads(std::thread& t)

    t.join();

int main() 
    for (int i = 0; i < 10; ++i) 
        threads.push_back(std::thread(worker) );
    
    std::for_each(threads.begin(),threads.end(),joinThreads);
    return 0;

【问题讨论】:

已添加代码.. 花了一段时间,因为我总是收到“错误”格式 Oo 的错误 【参考方案1】:

在 x86_64 上,printfdouble 参数将在不同的寄存器中传递给 long 参数,因此当您调用 printf("%ld\n", test) 时,编译器会将 test 放入浮点寄存器并调用函数.然后printf 实现在非浮点寄存器中查找参数,因为"%ld" 转换说明符告诉它期待long int 参数。因为实际参数与printf 查找的寄存器不在同一个寄存器中,所以找不到值。

当您添加下一行时,它会导致 tid 的值位于非浮点寄存器中,显然这允许 printf 找到它(但不要依赖它,它是未定义的行为和不可预测。)

解决方案:如果您不能正确使用printf,则根本不要使用它。要么使用为 double 指定的正确转换,即 "%f",要么将值存储在不同的类型中,或者使用 iostreams。

【讨论】:

+1 很好地解释了可能导致观察到的行为的原因。【参考方案2】:

格式说明符不正确,因为%ldlong,而不是double,因此程序具有未定义的行为。另外,std::hash&lt;&gt;::operator() 的返回值类型是size_t,而不是double。请改用(类型安全)std::cout

auto test = std::hash<std::thread::id>()(std::this_thread::get_id());
std::cout << test << std::endl;

【讨论】:

【参考方案3】:

你的输出是错误的。 %d 不是double,它代表十进制,即ints。

你想要的是

printf("%f\n", test);

当然,如果您首先使用 std::cout,这一切都不会发生,正如 hmjd 的回答所建议的那样。

【讨论】:

%ld 实际上是我想要的。在 gdb 中,输出是 [New Thread 0x7ffff308f700 (LWP 20234)] 十六进制值是 id。如果我用 %f 打印它,它的值不一样吗?还是我只是困惑? 那么为什么首先将哈希保存为双精度值?本来可以留一个size_t,这是std::hash的原始返回类型。 @baam,你很困惑。如果你将double 传递给printf,你必须告诉它你传递了一个双倍,使用"%f" ...如果那不是“实际上你想要的”(或认为你想要的)真的没关系) 因为你做错了会导致未定义的行为。如果你想要一个十六进制值,那么你不想要"%ld" "%f",因为它们都不打印十六进制值!如果你不能正确使用printf,那就不要使用它。 嗯.. 我可以发誓我以前用过 size_t,我也得到了一个零。但它现在工作正常.. 谢谢:)

以上是关于标准 C++ 线程 ID - 奇怪的行为的主要内容,如果未能解决你的问题,请参考以下文章

异步程序未异步运行的奇怪行为

C++ ostringstream 奇怪的行为

gcc 的奇怪行为。带有 和 = 的 C++ 对象定义是不是相等?

奇怪的编译器行为 (C++)

C++ while循环奇怪的行为

C++ 初始化奇怪的行为