ZHCADC4A September 2011 – March 2014
线程局部变量是特定于线程的变量,并具有静态存储持续时间。它们必须与全局及静态变量以类似的方式进行分配,如果它们已初始化,则在 .neardata 或 .fardata 段中分配,如果未初始化,则在 .bss 中分配。全局变量和静态变量每个进程只有一个拷贝,而线程局部变量每个线程需要一个单独的实例。
当程序为创建线程而进行调用时,线程由线程管理器创建。例如,OpenMP 应用中的并行区域会调用操作系统线程库,以创建工作线程;这些工作线程将加入/合并到并行区域的底部。
在线程创建期间,必须分配线程局部变量的存储并将其初始化。这意味着,每个线程 TLS 存储需要有一个初始化映像以用于初始化。如果使用线程局部存储,静态链接器(静态链接单元)的输出必须包含 TLS 初始化映像。静态链接单元称为模块。
单个模块的 TLS 初始化映像称为一个 TLS 映像。在创建线程的过程中,会为每个线程分配 TLS,并使用来自 TLS 映像的数据将其初始化。对于来自单个模块的线程局部变量,每个线程分配的存储器被称为 TLS 块。
在静态可执行文件模型中,静态链接器会生成从起始地址加载并执行的可执行文件。RTOS 和/或线程库作为可执行文件的一部分链接进来。在本例中,只有一个模块,因此只有一个 TLS 映像和一个 TLS 块。这可以简化 TLS 访问。主线程通常在程序初始化时创建;其他线程则由线程库创建。主线程的 TLS 块应由程序加载器分配并初始化(请参阅节 14.2)。线程库负责为其创建的线程分配 TLS 并将其初始化。
在 C6x Linux 系统中,程序(进程)是通过加载多个模块来创建的:一个可执行文件和零个或多个动态库。每个模块可以有一个 TLS 映像。程序的 TLS 映像包含所有模块的 TLS 映像。这称为 TLS 模板。通常,可执行文件和所有依赖模块都在进程启动时加载。它们称为初始加载的模块。Linux 程序也可以在启动后,通过调用 dlopen() 系统函数来加载动态库。启动后加载的模块称为经过 dlopen 处理的模块。在创建线程过程中,会根据 TLS 模板创建 TLS 块。由所有模块的 TLS 块组成的运行时结构称为 TLS。
如果是裸机动态链接,默认情况下只有初始加载的模块,它们可以连续放置以形成 TLS 模板。
有关 C6x 程序加载和动态链接的更多信息,请参阅Chapter14。