线程本地存储变量的地址 [英] Addresses of Thread Local Storage Variables

查看:147
本文介绍了线程本地存储变量的地址的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好吧,说我有

  __ thread int myVar; 

然后我将& myVar从一个线程传递给另一个线程......如果数据真的是本地,那么1个线程的TLS存储可能不会映射到其他线程地址空间中,实际上,您可能会认为它不应该是。这会导致SIGSEGV或其他东西。但是,系统可以将相同的地址映射到不同的页面。这是Linux用.tbss / .tdata做的事情吗?在这种情况下,传递一个变量的地址会给你错误变量的地址!你会得到你自己的本地副本,而不是你试图传递的副本。或者,是否所有东西都被共享并映射到不同的虚拟地址 - 允许你传递__线程变量的地址?



显然,一个应该被殴打和抨击以尝试传递线程本地存储到另一个线程通过传递它的地址。还有其他一些方法 - 例如复制到任何其他变量!但是,我很好奇,如果有人知道..


  1. 官方在这种情况下描述的行为
  2. 当前的GCC / Linux实现细节

- Evan

解决方案

至少对于x86来说,TLS是使用段寄存器执行的。默认段寄存器%ds 隐含在指向内存地址的指令中。在访问TLS时,线程使用另一个段寄存器 - 对于i386,%gs ,对于x86-64,使用%fs - 在调度线程时被保存/恢复,就像其他寄存器在上下文切换中一样。



因此,一个进程范围的变量可以用类似的方式访问: p>

  mov(ADDR) - > REG;将内存`myVar`加载到REG。 

这是隐含的:

  mov%DS:(ADDR) - > REG 

对于TLS,编译器生成:

  mov%FS:(ADDR) - > REG;将线程本地地址`myVar`加载到REG。 

实际上,即使变量的地址在不同的线程中看起来是相同的,例如,

  fprintf(stdout,%p \ n,& myVar); / *在单独的线程中... * / 

事实上每个线程都使用不同的值段寄存器,意味着它们映射到不同的物理内存区域。如果您要将地址从一个线程传递到另一个线程,则无法访问它在第一个线程中表示的内存 - 另一个段寄存器值在第二个 em> thread。

Windows使用相同的方案(它可以交换%fs %gs - 不确定)和OS X.至于其他架构,有一个深入的技术指南给ELF ABI的TLS。它缺少关于ARM架构的讨论,并且详细介绍了IA-64和Alpha,所以它显示了它的年龄。


OK, say that I have

__thread int myVar;

And I then pass &myVar from one thread to another ... If the data is truly "local", then the TLS storage of 1 thread may not be mapped into the other threads address space, and in fact, you could argue that it shouldn't be. This would result in a SIGSEGV or something. However, the system could just map the same address to a different page. Is this what Linux does with .tbss/.tdata? In that case, passing the address of a variable would give you the address of the wrong variable! You'd get your own local copy and not the copy you tried to pass. Or, is everything shared and mapped to different virtual addresses - allowing you to pass around addresses of __thread vars?

Obviously, one should be beaten and flogged for trying to pass thread local storage to another thread by passing its address. There are a million other ways - copying to any other variable for example! But, I was curious if anyone knew ..

  1. The official described behavior in this situation
  2. The current GCC/Linux implementation details

-- Evan

解决方案

For x86 at least, TLS is performed using segment registers. The default segment register %ds is implicit in instructions that address memory. When accessing TLS, a thread uses another segment register - %gs for i386 and %fs for x86-64 - which is saved/restored when a thread is scheduled, just as other registers are in a context switch.

So a process-wide variable might be accessed with something like:

mov (ADDR) -> REG ; load memory `myVar` to REG.

which is implicitly:

mov %DS:(ADDR) -> REG

For TLS, the compiler generates:

mov %FS:(ADDR) -> REG ; load thread-local address `myVar` to REG.

In effect, even if the address of the variable appears to be the same in different threads, e.g.,

fprintf(stdout, "%p\n", & myVar); /* in separate threads... */

the fact each thread is using a different value for the segment register, means that they map to different regions of physical memory. If you were to pass an address from one thread to another, you couldn't access the memory it represents in the first thread - a different segment register value is in effect in the second thread.

The same scheme is used by Windows (it may interchange the roles of %fs and %gs - not sure), and OS X. As for other architectures, there's an in-depth technical guide to TLS for the ELF ABI. It's missing a discussion of the ARM architecture, and has details on IA-64 and Alpha, so it's showing its age.

这篇关于线程本地存储变量的地址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆