void a() { ... } void b() { ... } struct X { X() { b(); } }; void f() { a(); static X x; ... }
Suppose f is called several times from various threads (potentially connected) after entering main. (and, of course, the only calls a and b are those that were discussed above)
When the above code is compiled with gcc g ++ 4.6 in -std = gnu ++ 0x mode:
Q1. Is it guaranteed that a () will be called at least once and return before b () is called? That is, to ask, when you first call f (), is the constructor x, called at the same time a local local variable (not static) with automatic duration (for example, not in global static initialization time)?
Q2. Is it guaranteed that b () will be called exactly once? Even if two threads execute f for the first time at the same time on different cores? If so, through which specific mechanism generates GCC code that provides synchronization? Edit : Also, can one of the threads calling f () access x before the constructor of X is returned?
Update: I am trying to compile an example and decompile an investigation mechanism ...
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); }
Then:
$ 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
I do not see the synchronization mechanism? Or is it added to linktime?
Update2: Well, when I bind it, I see it ...
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
He surrounds him with __cxa_guard_acquire and __ cxa_guard_release , whatever they do.