在多线程术语中,经常听到一个词就是“线程局部存储”,英文Thread-local storage,简称TLS。我们今天就来看看这到底是一个什么样的神秘东西。
1 在讲解之前,我们先来看一个例子
#include <QDebug>
int invoke_count =0; // 用来记录调用common_function函数的次数
void common_function ()
{
++
invoke_count;
//...
}
void print_count ()
{
qDebug () << "invoke_count = " << invoke_count;
}
int main()
{
common_function();
common_function();
common_function();
print_count();
}
这是一个很简单的例子,我定义了一个全局变量invokecount,每次调用完common_function时,invoke_count自增1,从而可以跟踪函数common_function被调用的次数。在main函数中,调用common_function三次,print_count打印为3。
2 现在,再修改一下例子
int invoke_count = 0; // 用来记录调用common_function函数的次数
void common_function()
{
++invoke_count;
//...
}
void print_count()
{
qDebug() << "invoke_count = " << invoke_count;
}
class MyThread1: public QThread
{
protected:
void run()
{
//...
for (int j = 0; j < 3; j++)
{
common_function();
}
//...
}
};
class MyThread2: public QThread
{
protected:
void run()
{
//...
for (int j = 0; j < 5; j++)
{
common_function();
}
//...
}
};
int main()
{
MyThread1 t1;
MyThread2 t2;
t1.start();
t2.start();
t1.wait();
t2.wait();
print_count();
}
小豆君在这里增加了两个线程类 ,MyThread1和MyThread2,MyThread1调用common_function共3次,MyThread2调用5次,最后打印common_function为8次。
3 再次修改
现在我们想分别跟踪统计MyThread1和MyThread2调用common_function的次数,显然全局变量、局部静态变量、局部变量已经无法满足要求,那要如何做到呢。
这时就用到了线程局部存储,在Qt中对应为QThreadStorage。
你可以直接运行下面的示例,看一下输出效果。
以下是输出:
大家看到了吗,结果输出了正确的值,虽然invoke_count和thread_name看起来像是全局变量,但是三个线程(主线程,t1,t2)使用它们时,这两个变量却只属于各自的线程,它们相对于各自线程是全局的,而对于整个进程却是局部的。而这就是线程局部存储的意义所在。
下面是QThreadStorage的介绍:
1)QThreadStorage类提供每个线程的数据存储。这使得由它创建的变量在线程范围内是全局的,而在进程范围内是局部的。
2)QThreadStorage是一个的模板类。
3)你可以使用localData()访问数据,setLocalData()设置数据。hasLocalData()函数允许你确定以前是否使用setLocalData()函数设置过数据。这对于惰性初始化是很有用的。
4)如果模板中的T是指针类型,那么在线程退出时会自动删除它。