linux - 使用使用 clone() 创建的线程时,线程本地存储不起作用
问题描述
下面的程序使用 Linux 的clone()
系统调用创建了 10 个线程。静态变量tls
具有 C11thread_local
属性。线程执行该child_func
函数,该函数只是增加tls
变量并将增加的值存储在参数指向的位置arg
。递增的值存储在数组中,每个线程一个tlsvals
。该main
函数等待线程完成,然后打印变量的十个实例的tls
值。(我在这个版本的代码中跳过了错误检查和释放分配的堆栈,以保持示例简短。)
#define _GNU_SOURCE
#include <sched.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <threads.h> /* For thread_local. */
#define NTHREADS 10
static thread_local int tls = 0;
static int child_func(void *arg)
{
tls++;
*((int *)arg) = tls;
return 0;
}
int main(int argc, char** argv)
{
int tlsvals[NTHREADS];
for (int n = 0; n < NTHREADS; n++) {
const int STACK_SIZE = 65536;
if (clone(child_func, malloc(STACK_SIZE) + STACK_SIZE, CLONE_VM | SIGCHLD, tlsvals+n) == -1) {
perror("clone");
exit(1);
}
}
int ret, status;
while ((ret = wait(&status)) != -1)
;
for (int *p = tlsvals; p < tlsvals + NTHREADS; p++)
printf("The value of tls is %d\n", *p);
return 0;
}
由于tls
变量标记为thread_local
,我希望程序打印十行The value of tls is 1
,因为每个线程都会从其初始零值增加一次变量。相反,我得到以下输出:
The value of tls is 1
The value of tls is 3
The value of tls is 2
The value of tls is 4
The value of tls is 5
The value of tls is 6
The value of tls is 7
The value of tls is 8
The value of tls is 9
The value of tls is 10
因此,该tls
变量似乎根本不是线程本地的,而是由所有线程共享的,并且每个线程都会增加相同的变量。
该代码是使用以下命令行在 x86_64 上使用 GCC 版本 9.1.0 编译的:
gcc -O2 -Wall -std=c11 tfoo.c -o tfooc
我还尝试使用 GCC 特定__thread
属性而不是thread_local
,结果相同。
查看 GCC 生成的程序集,我可以看到变量是通过%fs
寄存器访问的,它应该是:
child_func:
.LFB24:
.cfi_startproc
movl %fs:tls@tpoff, %eax
addl $1, %eax
movl %eax, %fs:tls@tpoff
movl %eax, (%rdi)
xorl %eax, %eax
ret
.cfi_endproc
我在做什么错,或者thread_local
在 Gcc 中的实现中是否存在错误?
解决方案
推荐阅读
- javascript - Wordpress 更改特定帖子类别的 :after 元素的 HTML 内容
- python - 您如何检查列表的项目是否等于同一列表中的另一个项目
- java - 如何循环遍历计时器类以延迟时间?
- r - 如何“真正”转换 R 中的变量
- python - 从 Google GitHub 存储库加载 JSON 数据
- kubernetes - 运行 kubernetes 集群的虚拟机会定期宕机
- entity-framework - 多个项目中的实体框架迁移
- html - html.erb 文件中的类名分隔
- php - 如何将选定的下拉值存储到会话变量中并显示在另一个页面上
- javascript - 为什么 async / await 函数运行两次?