C++ 11 中的 Thread Local Storage (TLS)应用——实际效果就是将全局变量在各个线程都copy一份,互不干扰独立使用

发布时间 2023-09-19 18:00:15作者: bonelee

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_localstatic 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 来为每个线程存储错误信息,从而避免这个问题。