G++ 4.6 -std=gnu++0x: синхронизация вызова конструктора статической локальной переменной и безопасность потоков

void a() { ... }
void b() { ... }

struct X
{
    X() { b(); }
};

void f()
{
    a();
    static X x;
    ...
}

Предположим, что f вызывается несколько раз из разных потоков (потенциально конфликтных) после входа в main. (и, конечно, единственные вызовы a и b показаны выше)

Когда приведенный выше код скомпилирован с gcc g++ 4.6 в -std=gnu++0x режим:

Q1.Гарантируется ли, что a() будет вызван хотя бы один раз и завершится до вызова b()? То есть при первом вызове f() вызывается ли конструктор x одновременно с локальной переменной автоматической длительности (нестатической) (а не во время глобальной статической инициализации, например)?

Q2. Гарантируется ли, что b() будет вызван ровно один раз? Даже если два потока выполняют f в первый раз одновременно на разных ядрах? Если да, с помощью какого конкретного механизма сгенерированный код GCC обеспечивает синхронизацию? Редактировать: Кроме того, может ли один из потоков, вызывающих f(), получить доступ к x до возврата конструктора X?

Обновление: Я пытаюсь скомпилировать пример и декомпилировать, чтобы исследовать механизм. ..

test.cpp:

struct X;

void ext1(int x);
void ext2(X& x);

void a() { ext1(1); }
void b() { ext1(2); }

struct X
{
    X() { b(); }
};

void f()
{
    a();
    static X x;
    ext2(x);
}

Тогда:

$ g++ -std=gnu++0x -c -o test.o ./test.cpp
$ objdump -d test.o -M intel > test.dump

test.dump:

test.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <_Z1av>:
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   bf 01 00 00 00          mov    edi,0x1
   9:   e8 00 00 00 00          call   e <_Z1av+0xe>
   e:   5d                      pop    rbp
   f:   c3                      ret    

0000000000000010 <_Z1bv>:
  10:   55                      push   rbp
  11:   48 89 e5                mov    rbp,rsp
  14:   bf 02 00 00 00          mov    edi,0x2
  19:   e8 00 00 00 00          call   1e <_Z1bv+0xe>
  1e:   5d                      pop    rbp
  1f:   c3                      ret    

0000000000000020 <_Z1fv>:
  20:   55                      push   rbp
  21:   48 89 e5                mov    rbp,rsp
  24:   41 54                   push   r12
  26:   53                      push   rbx
  27:   e8 00 00 00 00          call   2c <_Z1fv+0xc>
  2c:   b8 00 00 00 00          mov    eax,0x0
  31:   0f b6 00                movzx  eax,BYTE PTR [rax]
  34:   84 c0                   test   al,al
  36:   75 2d                   jne    65 <_Z1fv+0x45>
  38:   bf 00 00 00 00          mov    edi,0x0
  3d:   e8 00 00 00 00          call   42 <_Z1fv+0x22>
  42:   85 c0                   test   eax,eax
  44:   0f 95 c0                setne  al
  47:   84 c0                   test   al,al
  49:   74 1a                   je     65 <_Z1fv+0x45>
  4b:   41 bc 00 00 00 00       mov    r12d,0x0
  51:   bf 00 00 00 00          mov    edi,0x0
  56:   e8 00 00 00 00          call   5b <_Z1fv+0x3b>
  5b:   bf 00 00 00 00          mov    edi,0x0
  60:   e8 00 00 00 00          call   65 <_Z1fv+0x45>
  65:   bf 00 00 00 00          mov    edi,0x0
  6a:   e8 00 00 00 00          call   6f <_Z1fv+0x4f>
  6f:   5b                      pop    rbx
  70:   41 5c                   pop    r12
  72:   5d                      pop    rbp
  73:   c3                      ret    
  74:   48 89 c3                mov    rbx,rax
  77:   45 84 e4                test   r12b,r12b
  7a:   75 0a                   jne    86 <_Z1fv+0x66>
  7c:   bf 00 00 00 00          mov    edi,0x0
  81:   e8 00 00 00 00          call   86 <_Z1fv+0x66>
  86:   48 89 d8                mov    rax,rbx
  89:   48 89 c7                mov    rdi,rax
  8c:   e8 00 00 00 00          call   91 <_Z1fv+0x71>

Disassembly of section .text._ZN1XC2Ev:

0000000000000000 <_ZN1XC1Ev>:
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   48 83 ec 10             sub    rsp,0x10
   8:   48 89 7d f8             mov    QWORD PTR [rbp-0x8],rdi
   c:   e8 00 00 00 00          call   11 <_ZN1XC1Ev+0x11>
  11:   c9                      leave  
  12:   c3                      ret    

Я не вижу механизма синхронизации? Или он добавляется во время ссылки?

Update2: Хорошо, когда я связываю его, я вижу его...

400973: 84 c0                   test   %al,%al
400975: 75 2d                   jne    4009a4 <_Z1fv+0x45>
400977: bf 98 20 40 00          mov    $0x402098,%edi
40097c: e8 1f fe ff ff          callq  4007a0 <__cxa_guard_acquire@plt>
400981: 85 c0                   test   %eax,%eax
400983: 0f 95 c0                setne  %al
400986: 84 c0                   test   %al,%al
400988: 74 1a                   je     4009a4 <_Z1fv+0x45>
40098a: 41 bc 00 00 00 00       mov    $0x0,%r12d
400990: bf a0 20 40 00          mov    $0x4020a0,%edi
400995: e8 a6 00 00 00          callq  400a40 <_ZN1XC1Ev>
40099a: bf 98 20 40 00          mov    $0x402098,%edi
40099f: e8 0c fe ff ff          callq  4007b0 <__cxa_guard_release@plt>
4009a4: bf a0 20 40 00          mov    $0x4020a0,%edi
4009a9: e8 72 ff ff ff          callq  400920 <_Z4ext2R1X>
4009ae: 5b                      pop    %rbx
4009af: 41 5c                   pop    %r12
4009b1: 5d                      pop    %rbp

Он окружает его __cxa_guard_acquire и __cxa_guard_release, что бы они ни делали.

6
задан Andrew Tomazos 2 March 2012 в 14:23
поделиться