这处线程本地变量可不是简单的函数中的本地变量。线程除了可以共享存在于进程内的全局变量外,还可以有属于自己的线程本地变量。线程本地变量的值只能够在某个具体线程的生存期内可用。变量的实际存储空间会在线程开始时分配,线程结束时回收。线程不会对这些变量的读写操作产生数据竞争。
#include <stdio.h>
#include <threads.h>
#include <stdatomic.h>
#define THREAD_COUNT 10
#define THREAD_LOOP 10000
_Thread_local int counter = 0; // 定义一个线程本地变量
int run(void *arg){
for(int i = 0; i < THREAD_LOOP; i++){
counter++; // 对属于当前线程的线程本地变量累加10000次
}
return counter; // 返回累加的结果
}
int main(void){
#ifndef __STDC_NO_THREADS__
int sum = 0;
int result = 0;
thrd_t threads[THREAD_COUNT];
for(int i = 0; i < THREAD_COUNT; i++){
thrd_create(&threads[i],run,NULL); // 创建线程
}
for(int i = 0; i < THREAD_COUNT; i++){
thrd_join(threads[i],&result); // 有result接受线程累加的结果
sum += result;
}
printf("value is %d.\n",sum);
#endif
return 0;
}
~/Desktop$ gcc sha.c -o sha
~/Desktop$ ./sha
value is 100000.
使用 _Thread_local 关键字(或使用宏 thread_local),将全局变量 counter 标记为线程本地变量。每个线程将会在创建时生成仅属于当前线程的变量 counter。因此线程在对 counter 变量进行累加时,便不会受到其他线程的影响。线程本地变量还有一个用途:用来存储线程独有的一些信息,如错误信息。
除了以关键字来定义线程本地变量的方式之外,标准库还提供了一系列的函数来实现同样的目的。区别在于,通过 tss_create 等函数来创建线程本地变量时,还可以为其指定对应的析构函数。这样,当线程退出时,便可以确保相应的线程本地资源(比如堆内存)能够以正确的方式被清理。
- tss_create:创建新的线程本地变量,并指定它的析构函数
- tss_get:读取一个线程本地变量
- tss_set:修改一个线程本地变量
- tss_delete:销毁一个线程本地变量,释放其资源