我知道这是一个经常被问到的问题,但由于有很多变种,我想重新陈述它,并希望有一个反映当前状态的答案.就像是
Logger& g_logger() {
static Logger lg;
return lg;
}
Run Code Online (Sandbox Code Playgroud)
变量lg的构造函数是否保证只运行一次?
我从以前的答案中知道,在C++ 03中,这不是; 在C++ 0x草案中,这是强制执行的.但我想要一个更明确的答案
我对thread_localC++ 11中的描述感到困惑.我的理解是,每个线程在函数中都有唯一的局部变量副本.所有线程都可以访问全局/静态变量(可能使用锁进行同步访问).和thread_local变量的所有线程都是可见的,但只能由他们为其定义线程修改?这是对的吗?
我非常有信心在程序启动时分配(并初始化,如果适用)全局声明的变量.
int globalgarbage;
unsigned int anumber = 42;
Run Code Online (Sandbox Code Playgroud)
但是在函数中定义的静态的呢?
void doSomething()
{
static bool globalish = true;
// ...
}
Run Code Online (Sandbox Code Playgroud)
globalish分配的空间是什么时候?我猜测程序什么时候开始.但是它也被初始化了吗?或者它doSomething()是在第一次调用时初始化的?
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.是否有一些合理的方法(标准因为我希望它是便携式的)来做到这一点?
如何定义不在不同线程之间共享的本地静态变量(在函数调用之间保持其值)?
我正在寻找C和C++的答案
我有一个程序,用于thread_local std::shared_ptr管理一些主要在本地线程访问的对象。但是,当线程加入并且线程局部shared_ptr正在析构时,如果程序是由MinGW(Windows 10)编译的,那么在调试时总是会出现SIGSEGV。以下是重现该错误的最少代码:
// main.cpp
#include <memory>
#include <thread>
void f() {
thread_local std::shared_ptr<int> ptr = std::make_shared<int>(0);
}
int main() {
std::thread th(f);
th.join();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如何编译:
g++ main.cpp -o build\main.exe -std=c++17
Run Code Online (Sandbox Code Playgroud)
编译器版本:
>g++ --version
g++ (x86_64-posix-seh-rev2, Built by MinGW-W64 project) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Run Code Online (Sandbox Code Playgroud)
使用 gdb …
thread_local在块范围内使用变量有什么用?
如果一个可编译的示例有助于说明问题,这里是:
#include <thread>
#include <iostream>
namespace My {
void f(int *const p) {++*p;}
}
int main()
{
thread_local int n {42};
std::thread t(My::f, &n);
t.join();
std::cout << n << "\n";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出: 43
在示例中,新线程有自己的,n但(据我所知)不能用它做任何有趣的事情,所以为什么要麻烦呢?新线程自己的n有什么用吗?如果它没有用,那又有什么意义呢?
当然,我认为有是一个点。我只是不知道这有什么意义。这就是我问的原因。
如果新线程自己n想要(如我所想)在运行时由 CPU 进行特殊处理——也许是因为,在机器代码级别,人们无法n通过从新线程的基指针的预先计算的偏移量以正常方式访问自己的线程堆栈——那我们岂不是白白浪费机器周期和电力?然而即使不需要特殊处理,仍然没有收获!不是我能看到的。
那么为什么thread_local在块范围内?
参考
thread_local和其他存储类int main()
{
thread_local int n;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码在C ++ 11中合法。
根据cppreference:
thread_local仅在名称空间范围内声明的对象,在块范围内声明的对象和静态数据成员才允许使用关键字。
我只是好奇:
局部变量始终位于当前线程的堆栈上,因此它始终是线程局部的。在这种情况下thread_local int n;完全相同int n;。
为什么C ++ 11允许将局部变量声明为thread_local,而不是显式禁用它以避免滥用?
我有一堆线程,每个线程都需要一个线程安全的随机数。由于在我的真实程序中,线程是重复生成和连接的,所以我不想创建random_device并且mt19937每次进入一个调用相同函数的新并行区域时,所以我将它们设置为静态:
#include <iostream>
#include <random>
#include <omp.h>
void test(void) {
static std::random_device rd;
static std::mt19937 rng(rd());
static std::uniform_int_distribution<int> uni(1, 1000);
int x = uni(rng);
# pragma omp critical
std::cout << "thread " << omp_get_thread_num() << " | x = " << x << std::endl;
}
int main() {
# pragma omp parallel num_threads(4)
test();
}
Run Code Online (Sandbox Code Playgroud)
我无法放置它们,threadprivate因为错误 C3057:当前不支持“threadprivate”符号的动态初始化。一些消息来源说random_device和mt19937是线程安全的,但我还没有找到任何可以证明这一点的文档。