собственно, что означает, что он потенциально более тесно связан с компилятором.

ем эту простую функцию, которая увеличивает целое число под блокировкой, реализованнойstd::mutex:

#include <mutex>

std::mutex m;

void inc(int& i) {
    std::unique_lock<std::mutex> lock(m);
    i++;
}

Я ожидал бы, что это (после вставки) будет скомпилировано прямым способом к вызовуm.lock() приращениеi а потомm.unlock().

Проверка сгенерированной сборки на наличие последних версийgcc а такжеclangОднако мы видим дополнительное осложнение. Принимаяgcc версия первая:

inc(int&):
  mov eax, OFFSET FLAT:__gthrw___pthread_key_create(unsigned int*, void (*)(void*))
  test rax, rax
  je .L2
  push rbx
  mov rbx, rdi
  mov edi, OFFSET FLAT:m
  call __gthrw_pthread_mutex_lock(pthread_mutex_t*)
  test eax, eax
  jne .L10
  add DWORD PTR [rbx], 1
  mov edi, OFFSET FLAT:m
  pop rbx
  jmp __gthrw_pthread_mutex_unlock(pthread_mutex_t*)
.L2:
  add DWORD PTR [rdi], 1
  ret
.L10:
  mov edi, eax
  call std::__throw_system_error(int)

Это первые пару строк, которые интересны. Собранный код проверяет адрес__gthrw___pthread_key_create (который является реализацией дляpthread_key_create - функция для создания ключа локального потока), и если он равен нулю, он переходит к.L2 который реализует приращение в одной инструкции без какой-либо блокировки вообще.

Если он не равен нулю, он работает так, как ожидалось: блокирует мьютекс, делает приращение и разблокирует.

clang делает еще больше: проверяет адрес функциидваждыоднажды передlock и однажды передunlock:

inc(int&): # @inc(int&)
  push rbx
  mov rbx, rdi
  mov eax, __pthread_key_create
  test rax, rax
  je .LBB0_4
  mov edi, m
  call pthread_mutex_lock
  test eax, eax
  jne .LBB0_6
  inc dword ptr [rbx]
  mov eax, __pthread_key_create
  test rax, rax
  je .LBB0_5
  mov edi, m
  pop rbx
  jmp pthread_mutex_unlock # TAILCALL
.LBB0_4:
  inc dword ptr [rbx]
.LBB0_5:
  pop rbx
  ret
.LBB0_6:
  mov edi, eax
  call std::__throw_system_error(int)

Какова цель этой проверки?

Может быть, это для поддержки случая, когда объектный файл в конечном итоге скомпилирован в двоичный файл без поддержки pthreads, а затем для возврата к версии без блокировки в этом случае? Я не смог найти никакой документации по этому поведению.

Ответы на вопрос(1)

Ваш ответ на вопрос