diff --git a/SingleSource/UnitTests/Atomic/CMakeLists.txt b/SingleSource/UnitTests/Atomic/CMakeLists.txt index 94ad97d2ca..1191626bfc 100644 --- a/SingleSource/UnitTests/Atomic/CMakeLists.txt +++ b/SingleSource/UnitTests/Atomic/CMakeLists.txt @@ -1,8 +1,18 @@ +# These tests output numerical values to improve debuggability. +# Setting FP_TOLERANCE causes the test checker to use fpcmp to compare +# test and expected output. +# Because the nonatomic output may vary wildly even in a passing run, +# we set FP_TOLERANCE high so the test will never fail due to +# differing numerical results. +# The tests each have their own correctness checking and will fail +# properly if something is actually wrong. set(FP_TOLERANCE 1000000) + +# Link the Clang built libatomic. execute_process(COMMAND ${CMAKE_C_COMPILER} --print-file-name=libclang_rt.atomic.so OUTPUT_VARIABLE _path_to_libatomic OUTPUT_STRIP_TRAILING_WHITESPACE) get_filename_component(_libatomic_dir ${_path_to_libatomic} DIRECTORY) -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${_path_to_libatomic} -Wl,-rpath=${_libatomic_dir}") +add_link_options("LINKER:${_path_to_libatomic},-rpath=${_libatomic_dir}") llvm_singlesource() diff --git a/SingleSource/UnitTests/Atomic/big_test.cpp b/SingleSource/UnitTests/Atomic/big_test.cpp index 24b607b03a..88cc71cc9e 100644 --- a/SingleSource/UnitTests/Atomic/big_test.cpp +++ b/SingleSource/UnitTests/Atomic/big_test.cpp @@ -50,26 +50,24 @@ #include "util.h" static constexpr int kBigSize = 10; -struct big { +struct big_t { int v[kBigSize]; }; // The big struct cmpxchg test is identical to the numeric cmpxchg test, except // each element of the underlying array is incremented. -void looper_big_cmpxchg(big *abig, big &bbig, int success_model, +void looper_big_cmpxchg(big_t *abig, big_t &bbig, int success_model, int fail_model) { for (int n = 0; n < kIterations; ++n) { - big desired, expected = {}; + big_t desired, expected = {}; do { desired = expected; - for (int k = 0; k < kBigSize; ++k) { + for (int k = 0; k < kBigSize; ++k) desired.v[k]++; - } } while (!__atomic_compare_exchange(abig, &expected, &desired, true, success_model, fail_model)); - for (int k = 0; k < kBigSize; ++k) { + for (int k = 0; k < kBigSize; ++k) bbig.v[k]++; - } } } @@ -78,32 +76,26 @@ void test_big_cmpxchg() { for (int success_model : atomic_compare_exchange_models) { for (int fail_model : atomic_compare_exchange_models) { - big abig = {}; - big bbig = {}; - for (int n = 0; n < kThreads; ++n) { + big_t abig = {}; + big_t bbig = {}; + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_big_cmpxchg, &abig, std::ref(bbig), success_model, fail_model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "CMPXCHG: "; std::cout << "atomic: "; - for (int n = 0; n < kBigSize; ++n) { + for (int n = 0; n < kBigSize; ++n) std::cout << abig.v[n] << " "; - } std::cout << "\n "; std::cout << "nonatomic: "; - for (int n = 0; n < kBigSize; ++n) { + for (int n = 0; n < kBigSize; ++n) std::cout << bbig.v[n] << " "; - } std::cout << "\n"; - for (int n = 0; n < kBigSize; ++n) { - if (lt(abig.v[n], bbig.v[n]) || abig.v[n] != kExpected) { + for (int n = 0; n < kBigSize; ++n) + if (lt(abig.v[n], bbig.v[n]) || abig.v[n] != kExpected) fail(); - } - } } } } diff --git a/SingleSource/UnitTests/Atomic/float_test.cpp b/SingleSource/UnitTests/Atomic/float_test.cpp index 8bd5ca8c9b..d8c0d083a4 100644 --- a/SingleSource/UnitTests/Atomic/float_test.cpp +++ b/SingleSource/UnitTests/Atomic/float_test.cpp @@ -61,28 +61,23 @@ void test_float_scalar_xchg() { for (int model : atomic_exchange_models) { T afloat = 0; T ffloat = 0; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_numeric_xchg_atomic, &afloat, model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_numeric_xchg_nonatomic, std::ref(ffloat), model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "SCALAR (FETCH ADD): " << "atomic: " << afloat << " " << "nonatomic: " << ffloat << "\n"; if (lt(afloat, ffloat) || afloat < expected * (1 - kEpsilon) || - afloat > expected * (1 + kEpsilon)) { + afloat > expected * (1 + kEpsilon)) fail(); - } } } @@ -97,26 +92,23 @@ void test_float_scalar_cmpxchg() { for (int fail_model : atomic_compare_exchange_models) { T afloat = 0; T ffloat = 0; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_numeric_cmpxchg, &afloat, std::ref(ffloat), success_model, fail_model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "SCALAR (FETCH ADD): " << "atomic: " << afloat << " " << "nonatomic: " << ffloat << "\n"; if (lt(afloat, ffloat) || afloat < expected * (1 - kEpsilon) || - afloat > expected * (1 + kEpsilon)) { + afloat > expected * (1 + kEpsilon)) fail(); - } } } } -void test_float() { +void test_floating_point() { printf("Testing float\n"); test_float_scalar_xchg(); test_float_scalar_cmpxchg(); @@ -130,6 +122,6 @@ int main() { printf("%d threads; %d iterations each; total of %d\n", kThreads, kIterations, kExpected); - test_float(); + test_floating_point(); printf("PASSED\n"); } diff --git a/SingleSource/UnitTests/Atomic/int_aligned_test.cpp b/SingleSource/UnitTests/Atomic/int_aligned_test.cpp index f5ab5d29c7..9c497b66b4 100644 --- a/SingleSource/UnitTests/Atomic/int_aligned_test.cpp +++ b/SingleSource/UnitTests/Atomic/int_aligned_test.cpp @@ -71,19 +71,16 @@ void test_int_fetch_add(T &aint, T &iint) { for (int model : atomic_fetch_models) { aint = 0; iint = 0; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_int_fetch_add, &aint, std::ref(iint), model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "FETCH ADD: " << "atomic: " << aint << " " << "nonatomic: " << iint << "\n"; - if (lt(aint, iint) || aint != val * kExpected) { + if (lt(aint, iint) || aint != val * kExpected) fail(); - } } } @@ -103,19 +100,16 @@ void test_int_fetch_sub(T &aint, T &iint) { for (int model : atomic_fetch_models) { aint = val * kExpected; iint = val * kExpected; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_int_fetch_sub, &aint, std::ref(iint), model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "FETCH SUB: " << "atomic: " << aint << " " << "nonatomic: " << iint << "\n"; - if (lt(iint, aint) || aint != 0) { + if (lt(iint, aint) || aint != 0) fail(); - } } } @@ -154,20 +148,17 @@ void test_int_fetch_and(T &aint, T &iint) { for (int model : atomic_fetch_models) { T acnt = 0, icnt = 0; aint = ~0, iint = ~0; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_int_fetch_and, n, &aint, std::ref(iint), &acnt, &icnt, model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "FETCH AND: " << "atomic: " << acnt << " " << "nonatomic: " << icnt << "\n"; - if (acnt != kExpected) { + if (acnt != kExpected) fail(); - } } } @@ -199,20 +190,17 @@ void test_int_fetch_or(T &aint, T &iint) { for (int model : atomic_fetch_models) { T acnt = 0, icnt = 0; aint = 0, iint = 0; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_int_fetch_or, n, &aint, std::ref(iint), &acnt, &icnt, model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "FETCH OR: " << "atomic: " << acnt << " " << "nonatomic: " << icnt << "\n"; - if (acnt != kExpected) { + if (acnt != kExpected) fail(); - } } } @@ -230,19 +218,16 @@ void test_int_fetch_xor(T &aint, T &iint) { for (int model : atomic_fetch_models) { aint = 0; iint = 0; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_int_fetch_xor, &aint, std::ref(iint), model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "FETCH XOR: " << "atomic: " << aint << " " << "nonatomic: " << iint << "\n"; - if (aint != 0) { + if (aint != 0) fail(); - } } } @@ -253,26 +238,21 @@ void test_int_xchg(T &aint, T &iint) { for (int model : atomic_exchange_models) { aint = 0; iint = 0; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_numeric_xchg_atomic, &aint, model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_numeric_xchg_nonatomic, std::ref(iint), model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "XCHG: "; print_int(aint, iint); - if (lt(aint, iint) || aint != val * kExpected) { + if (lt(aint, iint) || aint != val * kExpected) fail(); - } } } diff --git a/SingleSource/UnitTests/Atomic/int_misaligned_test.cpp b/SingleSource/UnitTests/Atomic/int_misaligned_test.cpp index 5fc51d0c70..00ea100200 100644 --- a/SingleSource/UnitTests/Atomic/int_misaligned_test.cpp +++ b/SingleSource/UnitTests/Atomic/int_misaligned_test.cpp @@ -79,20 +79,17 @@ void test_int_misaligned_fetch_add(misaligned &astruct, for (int model : atomic_fetch_models) { astruct.data = 0; istruct.data = 0; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_int_misaligned_fetch_add, std::ref(astruct), std::ref(istruct), model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "FETCH ADD: " << "atomic: " << astruct.data << " " << "nonatomic: " << istruct.data << "\n"; - if (lt(astruct.data, istruct.data) || astruct.data != val * kExpected) { + if (lt(astruct.data, istruct.data) || astruct.data != val * kExpected) fail(); - } } } @@ -114,20 +111,17 @@ void test_int_misaligned_fetch_sub(misaligned &astruct, for (int model : atomic_fetch_models) { astruct.data = val * kExpected; istruct.data = val * kExpected; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_int_misaligned_fetch_sub, std::ref(astruct), std::ref(istruct), model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "FETCH SUB: " << "atomic: " << astruct.data << " " << "nonatomic: " << istruct.data << "\n"; - if (lt(istruct.data, astruct.data) || astruct.data != 0) { + if (lt(istruct.data, astruct.data) || astruct.data != 0) fail(); - } } } @@ -144,7 +138,7 @@ void __attribute__((optnone)) looper_int_misaligned_fetch_and( __atomic_fetch_add(acnt, 1, model); do { desired = expected | mask; - } while (!__atomic_compare_exchange(&astruct.data, &expected, &desired, + } while (!__atomic_compare_exchange(&astruct.data, &expected, &desired, true, model, model)); } istruct.data &= ~mask; @@ -162,21 +156,18 @@ void test_int_misaligned_fetch_and(misaligned &astruct, for (int model : atomic_fetch_models) { T acnt = 0, icnt = 0; astruct.data = ~0, istruct.data = ~0; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_int_misaligned_fetch_and, n, std::ref(astruct), std::ref(istruct), &acnt, &icnt, model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "FETCH AND: " << "atomic: " << acnt << " " << "nonatomic: " << icnt << "\n"; - if (acnt != kExpected) { + if (acnt != kExpected) fail(); - } } } @@ -211,21 +202,18 @@ void test_int_misaligned_fetch_or(misaligned &astruct, for (int model : atomic_fetch_models) { T acnt = 0, icnt = 0; astruct.data = 0, istruct.data = 0; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_int_misaligned_fetch_or, n, std::ref(astruct), std::ref(istruct), &acnt, &icnt, model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "FETCH OR: " << "atomic: " << acnt << " " << "nonatomic: " << icnt << "\n"; - if (acnt != kExpected) { + if (acnt != kExpected) fail(); - } } } @@ -245,20 +233,17 @@ void test_int_misaligned_fetch_xor(misaligned &astruct, for (int model : atomic_fetch_models) { astruct.data = 0; istruct.data = 0; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_int_misaligned_fetch_xor, std::ref(astruct), std::ref(istruct), model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "FETCH XOR: " << "atomic: " << astruct.data << " " << "nonatomic: " << istruct.data << "\n"; - if (astruct.data != 0) { + if (astruct.data != 0) fail(); - } } } @@ -301,27 +286,22 @@ void test_int_misaligned_xchg(misaligned &astruct, misaligned &istruct) { for (int model : atomic_exchange_models) { astruct.data = 0; istruct.data = 0; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_int_misaligned_xchg_atomic, std::ref(astruct), model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_int_misaligned_xchg_nonatomic, std::ref(istruct), model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "XCHG: "; print_int(astruct.data, istruct.data); - if (lt(astruct.data, istruct.data) || astruct.data != val * kExpected) { + if (lt(astruct.data, istruct.data) || astruct.data != val * kExpected) fail(); - } } } @@ -348,27 +328,22 @@ void test_int_misaligned_xchg_n(misaligned &astruct, for (int model : atomic_exchange_models) { astruct.data = 0; istruct.data = 0; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_int_misaligned_xchg_n, std::ref(astruct), model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_int_misaligned_xchg_nonatomic, std::ref(istruct), model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "XCHG_N: "; print_int(astruct.data, istruct.data); - if (lt(astruct.data, istruct.data) || astruct.data != val * kExpected) { + if (lt(astruct.data, istruct.data) || astruct.data != val * kExpected) fail(); - } } } @@ -397,20 +372,17 @@ void test_int_misaligned_cmpxchg(misaligned &astruct, for (int fail_model : atomic_compare_exchange_models) { astruct.data = 0; istruct.data = 0; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_int_misaligned_cmpxchg, std::ref(astruct), std::ref(istruct), success_model, fail_model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "CMPXCHG: "; print_int(astruct.data, istruct.data); if (lt(astruct.data, istruct.data) || - astruct.data != static_cast(val) * kExpected) { + astruct.data != static_cast(val) * kExpected) fail(); - } } } } @@ -440,20 +412,17 @@ void test_int_misaligned_cmpxchg_n(misaligned &astruct, for (int fail_model : atomic_compare_exchange_models) { astruct.data = 0; istruct.data = 0; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_int_misaligned_cmpxchg_n, std::ref(astruct), std::ref(istruct), success_model, fail_model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "CMPXCHG_N: "; print_int(astruct.data, istruct.data); if (lt(astruct.data, istruct.data) || - astruct.data != static_cast(val) * kExpected) { + astruct.data != static_cast(val) * kExpected) fail(); - } } } } diff --git a/SingleSource/UnitTests/Atomic/misshapen_test.cpp b/SingleSource/UnitTests/Atomic/misshapen_test.cpp index 065946b23f..2940d7f37f 100644 --- a/SingleSource/UnitTests/Atomic/misshapen_test.cpp +++ b/SingleSource/UnitTests/Atomic/misshapen_test.cpp @@ -60,9 +60,8 @@ void looper_misshapen_xchg_atomic(misshapen *amis, int model) { unsigned char error[N] = {}; misshapen next, result; __atomic_load(amis, &next, model); - for (int k = 0; k < N; ++k) { + for (int k = 0; k < N; ++k) next.v[k]++; - } for (int n = 0; n < kIterations; ++n) { __atomic_exchange(amis, &next, &result, model); for (int k = 0; k < N; ++k) { @@ -76,9 +75,8 @@ void looper_misshapen_xchg_atomic(misshapen *amis, int model) { __atomic_load(amis, &expected, model); do { desired = expected; - for (int k = 0; k < N; ++k) { + for (int k = 0; k < N; ++k) desired.v[k] -= error[k]; - } } while (!__atomic_compare_exchange(amis, &expected, &desired, true, model, model)); } @@ -88,9 +86,8 @@ void looper_misshapen_xchg_nonatomic(misshapen &mmis, int model) { unsigned char error[N] = {}; misshapen next, result; __atomic_load(&mmis, &next, model); - for (int k = 0; k < N; ++k) { + for (int k = 0; k < N; ++k) next.v[k]++; - } for (int n = 0; n < kIterations; ++n) { result = mmis; mmis = next; @@ -105,9 +102,8 @@ void looper_misshapen_xchg_nonatomic(misshapen &mmis, int model) { __atomic_load(&mmis, &expected, model); do { desired = expected; - for (int k = 0; k < N; ++k) { + for (int k = 0; k < N; ++k) desired.v[k] -= error[k]; - } } while (!__atomic_compare_exchange(&mmis, &expected, &desired, true, model, model)); } @@ -119,37 +115,29 @@ void test_misshapen_xchg() { for (int model : atomic_exchange_models) { misshapen amis = {}; misshapen mmis = {}; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_misshapen_xchg_atomic, &amis, model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_misshapen_xchg_nonatomic, std::ref(mmis), model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "XCHG: "; std::cout << "atomic: "; - for (int n = 0; n < N; ++n) { + for (int n = 0; n < N; ++n) std::cout << unsigned(amis.v[n]) << " "; - } std::cout << "\n "; std::cout << "nonatomic: "; - for (int n = 0; n < N; ++n) { + for (int n = 0; n < N; ++n) std::cout << unsigned(mmis.v[n]) << " "; - } std::cout << "\n"; - for (int n = 0; n < N; ++n) { - if (amis.v[n] != kExpected % (1 << (8 * sizeof(amis.v[0])))) { + for (int n = 0; n < N; ++n) + if (amis.v[n] != kExpected % (1 << (8 * sizeof(amis.v[0])))) fail(); - } - } } } @@ -161,14 +149,12 @@ void looper_misshapen_cmpxchg(misshapen *amis, misshapen &mmis, misshapen desired, expected = {}; do { desired = expected; - for (int k = 0; k < N; ++k) { + for (int k = 0; k < N; ++k) desired.v[k]++; - } } while (!__atomic_compare_exchange(amis, &expected, &desired, true, success_model, fail_model)); - for (int k = 0; k < N; ++k) { + for (int k = 0; k < N; ++k) mmis.v[k]++; - } } } @@ -180,30 +166,24 @@ void test_misshapen_cmpxchg() { for (int fail_model : atomic_compare_exchange_models) { misshapen amis = {}; misshapen mmis = {}; - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool.emplace_back(looper_misshapen_cmpxchg, &amis, std::ref(mmis), success_model, fail_model); - } - for (int n = 0; n < kThreads; ++n) { + for (int n = 0; n < kThreads; ++n) pool[n].join(); - } pool.clear(); std::cout << "CMPXCHG: "; std::cout << "atomic: "; - for (int n = 0; n < N; ++n) { + for (int n = 0; n < N; ++n) std::cout << unsigned(amis.v[n]) << " "; - } std::cout << "\n "; std::cout << "nonatomic: "; - for (int n = 0; n < N; ++n) { + for (int n = 0; n < N; ++n) std::cout << unsigned(mmis.v[n]) << " "; - } std::cout << "\n"; - for (int n = 0; n < N; ++n) { - if (amis.v[n] != kExpected % (1 << (8 * sizeof(amis.v[0])))) { + for (int n = 0; n < N; ++n) + if (amis.v[n] != kExpected % (1 << (8 * sizeof(amis.v[0])))) fail(); - } - } } } }