std::mutex::lock() 产生奇怪的(和不必要的)汇编代码

C.M*_*.M. 7 c++ gcc c++11

我正在检查为我的一些代码生成的 asm,我的眼睛发现了一些有趣的东西:

#include <mutex>

std::mutex m;

void foo()
{
    m.lock();
}
Run Code Online (Sandbox Code Playgroud)

生成的汇编代码 (x86-64 gcc 9.2, -std=c++11 -O2):

foo():
        mov     eax, OFFSET FLAT:_ZL28__gthrw___pthread_key_createPjPFvPvE
        test    rax, rax
        je      .L10                  // (1) we can simply bypass lock() call?
        sub     rsp, 8
        mov     edi, OFFSET FLAT:m
        call    __gthrw_pthread_mutex_lock(pthread_mutex_t*)
        test    eax, eax
        jne     .L14                  // (2) waste of space that will never be executed
        add     rsp, 8
        ret
.L10:
        ret
.L14:
        mov     edi, eax
        call    std::__throw_system_error(int)
m:
        .zero   40
Run Code Online (Sandbox Code Playgroud)

问题:

  • 第 (1) 部分 - gcc 特定:
    • 它在做什么?(分配 TLS 条目?)
    • 该操作失败如何让我们悄悄地绕过lock()呼叫?
  • 第 (2) 部分——看起来每个编译器都受到影响:
    • std::mutex::lock() 可以按标准扔
    • ...但它永远不会使用正确的代码(如相关的 SO 帖子中所述),出于所有意图和目的std::mutex::lock()始终noexcept使用正确的代码
    • 是否可以让编译器知道,以便它停止发出不必要的测试和指令块(.L14如上)?

注意:我看不出 throw fromstd::mutex::lock()比简单的abort()ing更好。在这两种情况下,你的程序都被搞砸了(没有人希望它会失败),但至少在后一种情况下,你最终得到的汇编代码要小得多(“只为你使用的东西付费”,还记得吗?)。

Wer*_*nze 1

您似乎误解了 asm 输出。你看到的不是 foo 的代码,而是mutex::lock.

来自https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/mutex:

void lock() // in class mutex
{
    int __e = __gthread_recursive_mutex_lock(&_M_mutex);

    // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
    if (__e)
        __throw_system_error(__e);
}
Run Code Online (Sandbox Code Playgroud)

来自https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.0/gthr-default_8h-source.html:

static inline int __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
{
    return __gthread_mutex_lock (mutex);
}

static inline int __gthread_mutex_lock (__gthread_mutex_t *mutex)
{
    if (__gthread_active_p ())
        return pthread_mutex_lock (mutex);
    else
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

这些名称与您的 asm 代码不完全匹配,因此我可能查看了不同的 libstdc++ 源代码,但对我来说,它看起来像是编译器内联mutex::lock到您的函数中foo,并且它还内联了正在调用的函数mutex::lock。