quimica peso numero molecular masa entre ejemplos diferencia como calcula atomico atomica c++ multithreading c++11 mutex atomic

c++ - numero - peso atomico ejemplos



Atómica bool no protege el contador no atómico (1)

Encontré un problema con un mutex spinlock (básico) que no parece funcionar como se esperaba.

4 hilos están incrementando un contador no atómico que está protegido por este mutex. El resultado no coincide con el resultado esperado que hace que el mutex parezca roto.

salida de ejemplo:

result: 2554230 expected: 10000000

En mi entorno sucede bajo las siguientes condiciones:

  • flag es std::atomic<bool> , cualquier otra cosa como std::atomic<int> o std::atomic_flag (con test_and_set ) funciona bien.

  • compilado en X86_64 con gcc 6.3.1 y -O3 flag

Mi pregunta es, ¿qué podría explicar este comportamiento?

#include <iostream> #include <vector> #include <atomic> #include <thread> #include <mutex> #include <assert.h> class my_mutex { std::atomic<bool> flag{false}; public: void lock() { while (flag.exchange(true, std::memory_order_acquire)); } void unlock() { flag.store(false, std::memory_order_release); } }; my_mutex mut; static int counter = 0; void increment(int cycles) { for (int i=0; i < cycles; ++i) { std::lock_guard<my_mutex> lck(mut); ++counter; } } int main() { std::vector<std::thread> vec; const int n_thr = 4; const int n_cycles = 2500000; for (int i = 0; i < n_thr; ++i) vec.emplace_back(increment, n_cycles); for(auto &t : vec) t.join(); std::cout << " result: " << counter << std::endl; std::cout << "expected: " << n_cycles * n_thr << std::endl; }

editar

Por solicitud de Voo, aquí está la salida del ensamblaje para increment() ..

$ g++ -O3 increment.cpp $ gdb a.out Reading symbols from a.out...done. (gdb) disassemble increment Dump of assembler code for function increment(int): 0x0000000000401020 <+0>: mov 0x20122a(%rip),%ecx # 0x602250 <_ZL7counter> 0x0000000000401026 <+6>: test %edi,%edi 0x0000000000401028 <+8>: mov $0x1,%edx 0x000000000040102d <+13>: lea (%rdi,%rcx,1),%esi 0x0000000000401030 <+16>: jle 0x401058 <increment(int)+56> 0x0000000000401032 <+18>: nopw 0x0(%rax,%rax,1) 0x0000000000401038 <+24>: mov %edx,%eax 0x000000000040103a <+26>: xchg %al,0x20120c(%rip) # 0x60224c <mut> 0x0000000000401040 <+32>: test %al,%al 0x0000000000401042 <+34>: jne 0x401038 <increment(int)+24> 0x0000000000401044 <+36>: add $0x1,%ecx 0x0000000000401047 <+39>: cmp %ecx,%esi 0x0000000000401049 <+41>: mov %ecx,0x201201(%rip) # 0x602250 <_ZL7counter> 0x000000000040104f <+47>: movb $0x0,0x2011f6(%rip) # 0x60224c <mut> 0x0000000000401056 <+54>: jne 0x401038 <increment(int)+24> 0x0000000000401058 <+56>: repz retq End of assembler dump.


Su código es correcto. Es un error 80004 - [6 Regresión] carga no atómica movida a antes de carga atómica con std :: memory_order_acquire