C++ 11 中的 Thread Local Storage (TLS)应用——实际效果就是将全局变量在各个线程都copy一份,互不干扰独立使用
C++ 11 中的 Thread Local Storage (TLS)
线程本地存储 (TLS)是 C++ 11 中引入的一项功能,允许多线程程序中的每个线程拥有自己单独的变量实例。简而言之,我们可以说每个线程都可以有自己独立的变量实例。每个线程都可以访问和修改自己的变量副本,而不会干扰其他线程。
句法
thread_local int my_variable;
线程本地存储 (TLS) 的属性
- 生命周期: TLS 变量的生命周期从初始化时开始,到线程终止时结束。
- 可见性: TLS 变量在线程级别具有可见性。
- 范围: TLS 变量的范围取决于声明它们的位置
thread_local 存储的示例
示例1:
C++
// C++ Program to implement // thread_local Storage #include <iostream> #include <thread> using namespace std; thread_local int counter = 0; void increment_counter() { counter++; cout << "Thread " << this_thread::get_id() << " counter = " << counter << endl; } int main() { // Create first thread thread t1(increment_counter); // Create second thread thread t2(increment_counter); // Wait for the first thread to finish t1.join(); // Wait for the second thread to finish t2.join(); return 0; } |
输出
线程 140093779908160 计数器 = 1 线程 140093788300864 计数器 = 1
示例2:
C++
// C++ Program to demonstrate the use of thread-local // storage. #include <iostream> #include <thread> using namespace std; class Singleton { public : static Singleton& getInstance() { // Each thread will have its own instance of // Singleton thread_local Singleton instance; return instance; } void printMessage() { cout << "Hello from thread " << this_thread::get_id() << endl; } private : Singleton() = default ; }; void workerThread() { Singleton::getInstance().printMessage(); } int main() { // Create first thread thread t1(workerThread); // Create second thread thread t2(workerThread); // Wait for the first thread to finish t1.join(); // Wait for the second thread to finish t2.join(); return 0; } |
输出
你好,来自线程 139683844367936 你好,来自线程 139683852760640
静态线程本地存储
它允许每个线程拥有自己单独的静态变量实例。与 TLS 类似,每个线程都可以访问和修改自己的静态变量副本,而不影响其他线程,但具有静态存储持续时间,这意味着该变量在同一线程内多次调用函数时仍然存在。
例子:
C++14
// C++ Program to implement // Static Thread Local Storage #include <iostream> #include <thread> using namespace std; void thread_func() { // Static thread-local variable static thread_local int stls_variable = 0; // Increment the variable stls_variable += 1; cout << "Thread ID: " << this_thread::get_id() << ", Variable: " << stls_variable << endl; } int main() { thread t1(thread_func); thread t2(thread_func); t1.join(); t2.join(); return 0; } |
输出
线程 ID:140702226085440,变量:1 线程 ID:140702234478144,变量:1
规则和限制
- thread_local 不能与函数声明或定义一起使用。它只能用于具有静态存储持续时间的数据声明和定义。
- 如果我们使用说明符thread_local 声明任何局部变量,则它是隐式静态的。如果没有提供其他存储类,thread_local和static thread_local是等效的。
- 我们必须使用 thread_local 说明符来声明和定义线程局部对象。这适用于声明和定义出现在同一文件或单独文件中的情况。
结论
C++ 中的线程本地存储 (TLS) 允许每个线程拥有自己单独的变量实例。TLS 变量在每个线程中都有自己的生存期、可见性和范围。TLS 可用于维护线程特定的数据,而不会干扰其他线程。
Thread Local Storage (TLS) 在多线程编程中有很多实际应用。TLS 可以为每个线程提供一块私有的存储空间,每个线程可以在这块空间中存储和获取数据,而不会影响到其他线程。这在多线程编程中非常有用,因为它可以避免数据竞争和同步问题。
以下是一些使用 TLS 的实际应用场景:
1. 线程特定数据:有时,你可能需要为每个线程存储一些特定的数据,例如线程的 ID、状态或其他上下文信息。你可以使用 TLS 来存储这些数据。
2. 避免全局变量:全局变量在多线程环境中可能会引发数据竞争和同步问题。你可以使用 TLS 来替代全局变量,每个线程都有自己的变量副本,从而避免这些问题。
3. 性能优化:在一些情况下,使用 TLS 可以提高性能。例如,如果一个函数需要一个大的缓冲区,而这个函数在多个线程中都被频繁调用,那么每次调用都分配和释放缓冲区可能会影响性能。你可以使用 TLS 来为每个线程分配一个缓冲区,然后在多次调用之间重用这个缓冲区。
4. 错误处理:在一些编程环境中,例如 C,错误信息通常通过全局变量来传递。这在多线程环境中可能会引发问题,因为一个线程的错误可能会覆盖另一个线程的错误。你可以使用 TLS 来为每个线程存储错误信息,从而避免这个问题。