Thread Local Storage---__thread 关键字的使用方法

本文详细介绍了GCC中的__thread关键字,包括其使用规则、适用的数据类型限制及如何在多线程环境中确保变量隔离。同时提供了示例代码展示__thread变量在线程间的独立性。

转自:http://blog.youkuaiyun.com/yusiguyuan/article/details/22938671

  __thread是GCC内置的线程局部存储设施,存取效率可以和全局变量相比。__thread变量每一个线程有一份独立实体,各个线程的值互不干扰。可以用来修饰那些带有全局性且值可能变,但是又不值得用全局变量保护的变量。

       __thread使用规则:只能修饰POD类型(类似整型指针的标量,不带自定义的构造、拷贝、赋值、析构的类型,二进制内容可以任意复制memset,memcpy,且内容可以复原),不能修饰class类型,因为无法自动调用构造函数和析构函数,可以用于修饰全局变量,函数内的静态变量,不能修饰函数的局部变量或者class的普通成员变量,且__thread变量值只能初始化为编译器常量(值在编译器就可以确定const int i=5,运行期常量是运行初始化后不再改变const int i=rand()).

Thread Local Storage
   线程局部存储(tls)是一种机制,通过这一机制分配的变量,每个当前线程有一个该变量的实例.
  gcc用于实现tls的运行时模型最初来自于IA-64处理器的ABI,但以后被用到其它处理器上。它需要链接器(ld),动态连接器(ld.so)和系统库(libc.so,libpthread.so)的全力支持.因此它不是到处可用的。
     在用户层,用一个新的存储类型关键字:__thread表示这一扩展。例如:
                        __thread int i;
                          extern __thread struct state s;
                          static __thread char *p;
    __thread限定符(specifier)可以单独使用,也可带有extern或static限定符,但不能带有其它存储类型的限定符。
    __thread可用于全局的静态文件作用域,静态函数作用域或一个类中的静态数据成员。不能用于块作用域,自动或非静态数据成员。
    当应用addressof操作符于一个线程局部存储变量时,它被在运行时求值,返回该变量当前线程实例的地址。这样得到的地址可以被其它任何线程使用。当一个线程终止时,任何该线程中的线程局部存储变量都不再有效。静态初始化不会涉及到任何线程局部存储变量的地址。
     在c++中,如果一个线程局部存储变量有一个初始化器,它必须是常量表达式。


[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include<iostream>  
  2. #include<pthread.h>  
  3. #include<unistd.h>  
  4. using namespace std;  
  5. const int i=5;  
  6. __thread int var=i;//两种方式效果一样  
  7. //__thread int var=5;//  
  8. void* worker1(void* arg);  
  9. void* worker2(void* arg);  
  10. int main(){  
  11.     pthread_t pid1,pid2;  
  12.     //__thread int temp=5;  
  13.     static __thread  int temp=10;//修饰函数内的static变量  
  14.     pthread_create(&pid1,NULL,worker1,NULL);  
  15.     pthread_create(&pid2,NULL,worker2,NULL);  
  16.     pthread_join(pid1,NULL);  
  17.     pthread_join(pid2,NULL);  
  18.     cout<<temp<<endl;//输出10  
  19.     return 0;  
  20. }  
  21. void* worker1(void* arg){  
  22.     cout<<++var<<endl;//输出 6  
  23. }  
  24. void* worker2(void* arg){  
  25.     sleep(1);//等待线程1改变var值,验证是否影响线程2  
  26.     cout<<++var<<endl;//输出6  
  27. }  

程序输出:

6

6         //可见__thread值线程间互不干扰

10



-- Performing Test HAVE_GCC_THREAD_LOCAL_STORAGE -- Performing Test HAVE_GCC_THREAD_LOCAL_STORAGE - Success -- Performing Test HAVE_MSC_THREAD_LOCAL_STORAGE -- Performing Test HAVE_MSC_THREAD_LOCAL_STORAGE - Failed -- Performing Test HAVE_CONSTRUCTOR_ATTRIBUTE -- Performing Test HAVE_CONSTRUCTOR_ATTRIBUTE - Failed -- Performing Test HAVE_DESTRUCTOR_ATTRIBUTE -- Performing Test HAVE_DESTRUCTOR_ATTRIBUTE - Failed -- Performing Test HAVE_FALLTHROUGH_ATTRIBUTE -- Performing Test HAVE_FALLTHROUGH_ATTRIBUTE - Failed -- Performing Test HAVE_GCC_VOLATILE_MEMORY_PROTECTION -- Performing Test HAVE_GCC_VOLATILE_MEMORY_PROTECTION - Failed -- Performing Test HAVE_GCC_NARG_MACRO -- Performing Test HAVE_GCC_NARG_MACRO - Failed -- Performing Test HAVE_COMPILER__FUNC__ -- Performing Test HAVE_COMPILER__FUNC__ - Failed -- Performing Test HAVE_COMPILER__FUNCTION__ -- Performing Test HAVE_COMPILER__FUNCTION__ - Failed -- Performing Test HAVE_GCC_BOUNDED_ATTRIBUTE -- Performing Test HAVE_GCC_BOUNDED_ATTRIBUTE - Failed -- Performing Test HAVE_LD_VERSION_SCRIPT -- Performing Test HAVE_LD_VERSION_SCRIPT - Failed -- Check if the system is big endian -- Searching 16 bit integer -- Looking for sys/types.h -- Looking for sys/types.h - not found -- Looking for stddef.h -- Looking for stddef.h - not found -- Check size of unsigned short -- Check size of unsigned short - failed -- Check size of unsigned int -- Check size of unsigned int - failed -- Check size of unsigned long -- Check size of unsigned long - failed CMake Error at /usr/share/cmake-3.5/Modules/TestBigEndian.cmake:51 (message): no suitable type found Call Stack (most recent call first): ConfigureChecks.cmake:417 (test_big_endian) CMakeLists.txt:98 (include) -- Configuring incomplete, errors occurred! See also "/home/bba/work/BBA1_5/MBB_Platform/apps/public/libssh/build/CMakeFiles/CMakeOutput.log". See also "/home/bba/work/BBA1_5/MBB_Platform/apps/public/libssh/build/CMakeFiles/CMakeError.log". make/apps/pubapps/libssh.mk:9: recipe for target 'libssh' failed make: *** [libssh] Error 1
最新发布
10-08
你遇到的 CMake 配置错误如下: ``` CMake Error at /usr/share/cmake-3.5/Modules/TestBigEndian.cmake:51 (message): no suitable type found Call Stack (most recent call first): ConfigureChecks.cmake:417 (test_big_endian) CMakeLists.txt:98 (include) ``` 同时,日志中显示: - 多个编译器特性测试失败(如 `HAVE_CONSTRUCTOR_ATTRIBUTE`、`HAVE_FALLTHROUGH_ATTRIBUTE` 等) - 关键系统头文件未找到:`sys/types.h`, `stddef.h` - 基本数据类型大小探测失败:`unsigned short`, `int`, `long` 等 --- ## 🔴 根本原因分析 这些错误表明 **CMake 无法执行最基本的系统探测**,说明你的构建环境缺少以下关键组件之一或多个: ### ❌ 问题根源总结: | 错误表现 | 可能原因 | |--------|---------| | `Looking for sys/types.h - not found` | 缺少标准 C 头文件(glibc 开发包) | | 所有 `Check size of ...` 失败 | C 编译器不能运行“测试程序” | | `no suitable type found` | CMake 的 `TestBigEndian.cmake` 模块依赖基本类型存在,但找不到任何整型 | | 所有 attribute 测试失败 | 编译器调用异常或交叉编译配置不当 | > ✅ 这通常发生在: > - **缺少 glibc 开发包** > - **使用了错误的交叉编译工具链** > - **工具链路径不完整或环境变量设置错误** > - **目标平台架构与编译器不匹配** --- ## ✅ 解决方案 ### ✅ 第一步:确认是否为交叉编译? 你是本地原生编译还是交叉编译? #### 判断方法: ```bash which gcc # 如果输出 /usr/bin/gcc → 原生编译 # 如果输出类似 /opt/toolchain/arm-linux-gnueabi/bin/gcc → 交叉编译 ``` --- ### ✅ 方案一:【适用于原生编译】安装缺失的开发头文件(Ubuntu/Debian) 如果你是在 Linux 主机上原生编译,但缺少 `sys/types.h`,说明没有安装标准 C 库开发包。 #### ✔️ 安装命令: ```bash sudo apt update sudo apt install build-essential libc6-dev ``` 或者更具体地: ```bash sudo apt install gcc g++ make cmake sudo apt install libc6-dev-amd64-cross # 或对应架构 ``` > 💡 特别注意:`sys/types.h` 属于 `glibc` 开发包(即 `libc6-dev`),必须安装! --- ### ✅ 方案二:【适用于交叉编译】正确配置工具链和 sysroot 如果你是 **交叉编译嵌入式设备(如 ARM)**,你需要提供一个完整的 **sysroot** 和正确的编译器前缀。 #### 示例目录结构(假设你的工具链已安装): ``` /opt/toolchain/ ├── bin/ │ ├── arm-linux-gnueabi-gcc │ └── ... ├── arm-linux-gnueabi/ │ ├── include/ │ │ ├── sys/types.h │ │ └── stddef.h │ └── lib/ ``` #### 创建 Toolchain 文件:`toolchain.cmake` ```cmake set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR arm) # 工具链路径 set(TOOLCHAIN_PREFIX /opt/toolchain/arm-linux-gnueabi) # 编译器 set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}/bin/arm-linux-gnueabi-gcc) set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}/bin/arm-linux-gnueabi-g++) # sysroot set(CMAKE_SYSROOT ${TOOLCHAIN_PREFIX}) # 搜索路径设置 set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) ``` #### 使用方式: ```bash cd build rm -rf * # 清除旧缓存 cmake .. \ -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake \ -DCMAKE_BUILD_TYPE=Release make ``` --- ### ✅ 方案三:检查并修复环境变量 有时即使工具链存在,环境问题也会导致检测失败。 #### 检查: ```bash arm-linux-gnueabi-gcc -E -x c /dev/null -o /dev/null && echo "OK" || echo "FAIL" ``` 如果报错(如 `command not found` 或 `cannot find crt1.o`),说明: - 工具链未加入 `PATH` - 或者 `sysroot` 不完整 #### 修复 PATH: ```bash export PATH=/opt/toolchain/arm-linux-gnueabi/bin:$PATH ``` 然后重新运行 CMake。 --- ### ✅ 方案四:手动指定基础类型(极端情况) 仅当所有自动探测都失败且你知道目标平台字节序时可用(不推荐)。 在 `CMakeCache.txt` 或通过 `-D` 参数强制定义: ```bash cmake .. \ -DHAVE_STDDEF_H=1 \ -DHAVE_SYS_TYPES_H=1 \ -DCMAKE_C_FLAGS="-I/opt/toolchain/arm-linux-gnueabi/include" \ -DTEST_BIG_ENDIAN=0 # 小端系统(ARM/Intel) ``` 但这只是绕过问题,不能治本。 --- ## ✅ 如何验证修复成功? 创建一个最简单的测试程序: ```c // test.c #include <sys/types.h> #include <stddef.h> #include <stdio.h> int main() { printf("size: %zu\n", sizeof(unsigned long)); return 0; } ``` 尝试编译: ```bash gcc test.c -o test # 原生 arm-linux-gnueabi-gcc test.c -o test # 交叉 ``` ✅ 成功 → 表示头文件和库路径正常 ❌ 失败 → 继续排查工具链或开发包 --- ## ✅ 总结 | 问题 | 原因 | 解决方法 | |------|------|----------| | `sys/types.h` 找不到 | 缺少 `libc6-dev` 或交叉编译无 sysroot | 安装开发包或配置 toolchain | | 类型大小探测失败 | 编译器无法运行测试程序 | 检查工具链路径和权限 | | `no suitable type found` | CMake 无法获取基本整数类型 | 必须修复头文件和编译器 | | attribute 测试失败 | 编译器调用失败或选项不支持 | 先解决基础问题再看这些 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值