Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 程序集-线程安全局部变量_Multithreading_Assembly_Thread Local Storage - Fatal编程技术网

Multithreading 程序集-线程安全局部变量

Multithreading 程序集-线程安全局部变量,multithreading,assembly,thread-local-storage,Multithreading,Assembly,Thread Local Storage,我试图在汇编程序中使用线程安全的局部变量。 我在网上搜索过,但没有找到简单的东西 我目前正在使用GCC汇编程序,因为该程序是C代码和汇编代码的混合体,但最终的程序将包含多个平台/调用约定的代码 现在,我已经使用.lcommpseudo-op声明了我的变量。 据我所知,这些变量将放在.bss部分。 所以我猜它们将被所有线程共享 有没有一种方法可以直接在汇编中使用某种TLS变量,或者我应该使用特定于平台的实现,比如Windows上的pthread或\u declspec 希望足够清楚。如果需要更多信

我试图在汇编程序中使用线程安全的局部变量。 我在网上搜索过,但没有找到简单的东西

我目前正在使用GCC汇编程序,因为该程序是C代码和汇编代码的混合体,但最终的程序将包含多个平台/调用约定的代码

现在,我已经使用
.lcomm
pseudo-op声明了我的变量。 据我所知,这些变量将放在
.bss
部分。 所以我猜它们将被所有线程共享

有没有一种方法可以直接在汇编中使用某种TLS变量,或者我应该使用特定于平台的实现,比如Windows上的
pthread
\u declspec

希望足够清楚。如果需要更多信息,请毫不犹豫地询问

谢谢大家,

编辑

下面是有问题的代码:

.lcomm  stack0, 8
.lcomm  stack1, 8

.globl _XSRuntime_CallMethod
_XSRuntime_CallMethod:

    pushq   %rbp
    movq    %rsp,   %rbp

    xor     %rax,   %rax

    popq    stack0( %rip )
    popq    stack1( %rip )

    callq   *%rdi

    pushq   stack1( %rip )
    pushq   stack0( %rip )

    leave
    ret
基本上,它用于将调用重定向到C函数

C原型是:

extern uint64_t XSRuntime_CallMethod( void ( *m )( void * self, ... ), ... );
它将函数指针作为第一个参数,因此是
callq*%rdi
,因为我正在用SystemV ABI测试它

汇编代码非常简单,我希望保持这种方式,以便易于维护


问题是:如何使
stack0
stack1
变量线程安全经典的“局部变量”,即通过堆栈偏移访问的参数/变量/结果,本质上是线程安全的

如果您需要平台无关的“TLS”,请在恢复所有线程之前,将一些合适的结构/类实例作为创建参数在线程字段中传递给所有线程,然后将第一条消息传递给线程输入队列或其他任何内容

Rgds,
Martin

您可能应该使用(调用)TlsAlloc&
TlsFree
(或其其他操作系统等价物)来执行类似的操作。返回的索引可以存储在全局集中一次,只读变量,以便于使用


根据变量所包含的内容和使用它们的代码所做的工作,您可能可以避开原子操作,但这可能会产生问题。

您认为编译器如何实现线程局部变量?尝试用-S或/FAs编译这样的程序,您将看到。提示:它必须依赖操作系统特定的API或其他详细信息才能访问TLS存储。有时准备步骤隐藏在CRT中,但没有单一的方法

例如,最近MSVC是如何做到这一点的:

_TLS    SEGMENT
?number@@3HA DD 01H DUP (?)             ; number
_TLS    ENDS
EXTRN   __tls_array:DWORD
EXTRN   __tls_index:DWORD
_TEXT   SEGMENT
[...]
mov eax, DWORD PTR __tls_index
mov ecx, DWORD PTR fs:__tls_array
mov edx, DWORD PTR [ecx+eax*4]
mov eax, DWORD PTR ?number@@3HA[edx]
如您所见,它使用由CRT初始化的特殊变量

在最近的Linux上,GCC可以使用特定于TLS的重新定位:

.globl number
    .section    .tbss,"awT",@nobits
number:
    .zero   4
    .text
    [...]
    movl    %gs:number@NTPOFF, %eax

如果您想要可移植性,最好不要依赖这些特定于操作系统的细节,而是使用诸如pthread之类的通用API或使用Martin提出的基于堆栈的方法。但我想,如果您想要可移植性,就不会使用assembler:)

对assembler不太熟悉,所以:

.lcomm  stack0, 8
.lcomm  stack1, 8

.globl _XSRuntime_CallMethod
_XSRuntime_CallMethod:

    pushq   %rbp // save BP
    movq    %rsp,   %rbp // load BP with SP

    xor     %rax,   %rax  // clear AX

    popq    stack0( %rip )  // pop return address into STACK0
    popq    stack1( %rip )  // pop flags into stack1

    callq   *%rdi  // call the indirect procedure, so putting flags/return to         XSRuntime_CallMethod onto stack

    pushq   stack1( %rip ) // put caller flags onto stack
    pushq   stack0( %rip ) // put caller return onto stack

    leave // clean passed parameters from stack
    ret   // and back to caller
这就是它的工作原理,是吗

如果是这样的话,跳转到间接过程而不是调用它不是更容易吗?然后不需要任何额外的变量来保存调用方标志/返回&间接过程直接返回给调用方

只是一个建议-自从我做汇编程序

如果必须将调用者地址存储在某个位置,请取消SP的设置,(输入?),然后使用堆栈帧。其他任何东西在某个点上都可能是线程不安全的

Rgds, 马丁

好吧,使用TLS maybee不是线程不安全的,但是任何递归调用呢?您最终会在TLS中使用另一个堆栈来覆盖这一点,因此您也可以使用“SP”堆栈


Martin

如前所述,局部变量(基于堆栈)本质上是线程安全的,因为每个线程都有自己的堆栈

所有线程都可以访问的线程安全变量(不是基于堆栈的)可能最好使用自旋锁(或Windows NT引擎中的等效项,一个关键部分)来实现。这样的变量必须在访问前锁定、访问然后解锁。一种变体可能是读取是免费的,但写入必须通过锁定/解锁来设置框架


仅AFAIK编译器本身不实现线程安全变量。相反,它们提供了访问所需操作系统功能的lib函数。

在汇编程序中编写时,为什么要担心平台特定的问题?因为采用一种“跨平台”的方式会更容易,而且更易于维护。我不明白汇编是如何跨平台的。我以为每个平台都有不同的规则。是的,没错。我只是想尽量减少不同实现之间的差异。:)下次请尝试先问实际问题,而不是“[我决定用X来解决它,所以]我怎么做X?”谢谢你的回答。请查看编辑。。。我使用
.lcomm
使用两个变量。所以它们不在堆栈中。jmp实际上是解决方案。。。非常感谢;)