threadlocal 在代码中定义后,在不同的线程中会有不同的副本
先看代码
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <unistd.h>
thread_local unsigned int count = 1;
std::mutex cout_mutex; // 实际上这个锁没有用,下面代码不会发生争抢 count
void increase_count(const std::string& thread_name)
{
++count; // 在锁外修改 OK;这是线程局域变量; 线程安全; 是副本
std::lock_guard<std::mutex> lock(cout_mutex);
std::cout << "子线程 " << thread_name << ": " << count << '\n';
std::cout << "count 地址" << &count << '\n'; // 证明 count 是副本
}
int main()
{
std::thread a(increase_count, "a"), b(increase_count, "b");
{
sleep(1); // 为了让 main 函数的调用慢于 a、b 线程
std::lock_guard<std::mutex> lock(cout_mutex);
// 虽然 a、b 子线程先运行,都增加了 count 的值,但是主线程 count 的值依旧是 1
std::cout << "主线程: " << count << '\n';
std::cout << "count 地址" << &count << '\n';
}
a.join();
b.join();
}
/*
子线程 a: 2
count 地址0x600001be4000
子线程 b: 2
count 地址0x600001bf8000
主线程: 1
count 地址0x600001be0000
*/
如果使用局部变量去写这个代码,应该是这样,不是完全等价,但是意思一样
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <unistd.h>
unsigned int count = 1; // 这个变量假设不会被其他线程修改
std::mutex cout_mutex; // 实际上这个锁没有用,下面代码不会发生争抢 count
void increase_count(const std::string& thread_name)
{
unsigned int temp = count;
temp++;
std::lock_guard<std::mutex> lock(cout_mutex);
std::cout << "子线程 " << thread_name << ": " << temp << '\n';
std::cout << "count 地址" << &count << '\n'; // 全局变量 count 的地址一样
}
int main()
{
std::thread a(increase_count, "a"), b(increase_count, "b");
{
sleep(1); // 为了让 main 函数的调用慢于 a、b 线程
std::lock_guard<std::mutex> lock(cout_mutex);
// 虽然 a、b 子线程先运行,都增加了 count 的值,但是主线程 count 的值依旧是 1
std::cout << "主线程: " << count << '\n';
std::cout << "count 地址" << &count << '\n';
}
a.join();
b.join();
}
/*
子线程 a: 2
count 地址0x10268c000
子线程 b: 2
count 地址0x10268c000
主线程: 1
count 地址0x10268c000
*/
此外
如果真想定义线程内部的全局变量(线程内可见),建议参考 pthread_setspecific 和 pthread_getspecific
Linux线程私有数据Thread-specific Data(TSD) 详解_线程私有数据(thread specific data, tsd)_cheems~的博客-CSDN博客
通过一个 key 把变量存起来,又通过 key 把变量取出来,从而实现线程内部的全局变量