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。是否有一些合理的方法(标准因为我希望它是便携式的)来做到这一点?
答案 0 :(得分:71)
你只需要做
std::hash<std::thread::id>{}(std::this_thread::get_id())
获得size_t
。
来自cppreference:
std::hash
类的std::thread::id
模板特化允许用户获取线程标识符的哈希值。
答案 1 :(得分:27)
便携式解决方案是将您自己生成的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
类型仅用于比较,不用于算术(即在can上说:标识符)。即使operator<<
生成的文本表示是未指定,因此您不能依赖它作为数字的表示。
您还可以使用std::thread::id
值的映射到您自己的id,并在线程之间共享此映射(具有适当的同步),而不是直接传递id。
答案 2 :(得分:22)
另一个id(想法?^^)将使用stringstreams:
std::stringstream ss;
ss << std::this_thread::get_id();
uint64_t id = std::stoull(ss.str());
如果在出现问题的情况下不想要例外,请使用try catch ...
答案 3 :(得分:6)
一个想法是使用线程本地存储来存储变量 - 无论什么类型,只要它符合线程本地存储的规则 - 然后使用该变量的地址作为您的“线程ID ”。显然任何arithemetic都没有意义,但它将是一个完整的类型。
后人:
pthread_self()
返回pid_t
并且是posix。这对于便携式设备的某些定义是可移植的。
gettid()
,几乎肯定不是可移植的,但它确实返回了GDB友好值。
答案 4 :(得分: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以防止地狱般的问题:)与追捕这种bug相比,重写很容易。 :)
答案 5 :(得分:3)
thread::native_handle()
返回thread::native_handle_type
,这是long unsigned int
的typedef。
如果线程是默认构造的,则native_handle()返回0。 如果附加了OS线程,则返回值为非零(POSIX上为pthread_t)。
答案 6 :(得分: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。
答案 7 :(得分:2)
通过这种方式,应该工作:
std::stringstream ss;
ss << std::this_thread::get_id();
int id = std::stoi(ss.str());
请记住包含库sstream
答案 8 :(得分:1)
也许此解决方案对某人有用。在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];
}
答案 9 :(得分:1)
另一种选择:
#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;
}
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
即除了第一次调用该函数外,没有任何同步的单个分支将被正确预测。之后,仅一次内存访问就没有同步。
答案 10 :(得分:0)
不使用thread :: get_id()的主要原因是它在单个程序/进程中不是唯一的。这是因为一旦第一个线程完成,id就可以用于第二个线程。
这似乎是一个可怕的功能,但在c ++ 11中却是什么。