c++ - 并发使用中内联汇编的设计元素

标签 c++ c gcc assembly concurrency

我找不到关于我应该如何编写一段内联 asm 的简洁解释,以及并发使用 foo 函数可能引起的问题是什么包含 asm 代码。

我看到的问题是,在 asm 中,寄存器是唯一命名的,因此 1 个名称严格绑定(bind)到你的 cpu 的一个非常精确的部分,如果你正在编写,这是一个大问题1 段应该同时运行的代码,因为您不能简单地使用相同名称的额外寄存器。

另一个问题是 asm 并没有真正使用调用约定,您只需调用寄存器和/或值,有时调用寄存器意味着一个静默 Action 在另一个甚至没有明确显示在您的代码中的寄存器上;因此,如果我的 C/C++ 函数 foo 包含 asm 代码,我什至不能指望它会被打包并密封在自己的堆栈中。

现在 gcc 调用 extended asm我基本上可以声明输入和输出的去向,因此每个函数都可以使用自己的参数“as registers”,模式如下

   asm ( assembler template 
       : output               
       : input               
       : registers 
       );

假设我现在的主要目标是数学运算,我的函数只应该提供某种功能并执行一些计算(没有内部锁),那么扩展 asm 是否适合并发?我应该如何设计一 block 应该由并发应用程序使用的 asm?

目前我正在使用 gcc,但我想要一个关于一般 asm 设计的通用答案,我应该为这种代码片段提供.

最佳答案

您似乎误解了线程实际上是什么。让我们首先考虑一个单处理器系统。这些线程实际上并发运行,因为只有一个单元可以成功解码和执行它们。您的操作系统只是通过在其内部采用调度来创建运行多个线程(以及进程)的错觉:每个线程或进程都分配了一定的时间在处理器上执行。

这就是为什么当线程被执行时,它们不会覆盖彼此的寄存器。当当前执行的线程或进程被切换时,操作系统会要求处理器执行称为上下文切换的操作。简而言之,处理器在执行前一个任务/线程/进程时将其状态保存到某个由操作系统控制的内存区域。新任务/线程/进程从先前存储的状态恢复其上下文并继续执行。当这个任务/线程/进程在 CPU 上的时间片结束时,调度程序决定接下来要恢复哪个任务/线程/进程。时间片通常很小,这就是为什么您会产生多个代码流同时运行的错觉。请记住,这是一个非常非常非常的简化描述:有关详细信息,请参阅 CPU 手册或操作系统书籍。

多处理器系统的情况类似:唯一的异常(exception)是,有不止一个单元可以执行指令。对于多核处理器也是如此:每个内核都有自己的一组寄存器。基本内容保持不变 - 操作系统中的调度程序决定正在执行的代码是否实际上由一个处理器中的多个内核同时执行。

因此,您在这种情况下的顾虑是不成立的。然而,他们是出于非常正当的理由被提出来的。请记住,线程唯一共享的是主内存:每个线程都有自己的寄存器和堆栈。

让我回到有关 gcc 的扩展内联汇编的实际问题。编译器本身无法确定哪些寄存器被您编写的程序集修改了。这就是为什么你需要指定它。但是,一条指令在您无法控制的情况下修改寄存器是非常罕见的,而且它只发生在少数指令中——假设我们正在谈论 x86。此外,当您想从程序集内部引用 C/C++ 变量时,gcc 可以自行计算出目标/源操作数。事实上,这是首选方法,因为它为编译器留出了更多的优化空间。

考虑这段代码:

unsigned int get_cr0(void)
{
    unsigned int rc;
    __asm__ (
        "movl %%cr0, %0\n"
        : "=r"(rc)
        :
        :
    );
    return rc;
}

此函数的目的是返回控制寄存器cr0 的内容。这是一条特权指令,因此当您在用户模式下运行该程序时,该程序将无法运行,但现在这并不重要。看看我是如何在指令中放入%0,然后在输出列表中指定"=r"(rc)。这意味着编译器会自动将 %0 别名化为您的 rc 变量。您可以对输入/输出列表中指定的每个变量执行此操作。如您所见,它们从零开始编号。

我真的不记得使用未编码为操作数的寄存器的指令,所以我现在不能给你举个例子。在这种情况下,您需要将它们放在 clobber 列表中(最后一个)。我很确定你可以引用 this获取更多信息。

我也无法回答有关“通用 asm 设计”的任何问题,因为这是一个非标准扩展,因此因编译器而异。例如,64 位 Visual Studio 编译器根本不支持它。

关于c++ - 并发使用中内联汇编的设计元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21244104/

相关文章:

c++ - 使用 C++ API 进行数组选择和存储

c++ - 是否有 gcc 标志允许在 C++ 中进行 C 风格的隐式指针转换?

c - 为什么某些 C 编译器会在奇怪的地方设置函数的返回值?

C++ - isdigit 无法正常工作并导致永无止境的循环

c++ - 在混合 C 和 C++ 代码编程中捕获异常后对象未被销毁

C 编程 - 无法打印用户输入

c - 无论标志如何,来自二进制的 fread 返回相同

c - C中的通用 map 操作

gcc - DOS .COM 文件末尾的额外字节,使用 GCC 编译

C++通过类模板函数中的指针访问类方法