// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkMultiThreader.h" #include "vtkNew.h" #include "vtkObjectFactory.h" #include #include #include static std::atomic TotalAtomic(0); static std::atomic TotalAtomic64(0); static constexpr int Target = 1000000; static int Values32[Target + 1]; static int Values64[Target + 1]; static vtkMTimeType MTimeValues[Target]; static int NumThreads = 5; // uncomment the following line if you want to see // the difference between using atomics and not // #define SHOW_DIFFERENCE #ifdef SHOW_DIFFERENCE static int Total = 0; static vtkTypeInt64 Total64 = 0; #endif VTK_THREAD_RETURN_TYPE MyFunction(void*) { vtkNew AnObject; for (int i = 0; i < Target / NumThreads; i++) { #ifdef SHOW_DIFFERENCE Total++; Total64++; #endif int idx = ++TotalAtomic; Values32[idx] = 1; idx = ++TotalAtomic64; Values64[idx] = 1; AnObject->Modified(); MTimeValues[idx - 1] = AnObject->GetMTime(); } return VTK_THREAD_RETURN_VALUE; } VTK_THREAD_RETURN_TYPE MyFunction2(void*) { for (int i = 0; i < Target / NumThreads; i++) { --TotalAtomic; --TotalAtomic64; } return VTK_THREAD_RETURN_VALUE; } VTK_THREAD_RETURN_TYPE MyFunction3(void*) { for (int i = 0; i < Target / NumThreads; i++) { int idx = TotalAtomic += 1; Values32[idx]++; idx = TotalAtomic64 += 1; Values64[idx]++; } return VTK_THREAD_RETURN_VALUE; } VTK_THREAD_RETURN_TYPE MyFunction4(void*) { for (int i = 0; i < Target / NumThreads; i++) { TotalAtomic++; TotalAtomic += 1; TotalAtomic--; TotalAtomic -= 1; TotalAtomic64++; TotalAtomic64 += 1; TotalAtomic64--; TotalAtomic64 -= 1; } return VTK_THREAD_RETURN_VALUE; } int TestAtomic(int, char*[]) { #ifdef SHOW_DIFFERENCE Total = 0; Total64 = 0; #endif TotalAtomic = 0; TotalAtomic64 = 0; for (int i = 0; i <= Target; i++) { Values32[i] = 0; Values64[i] = 0; } vtkNew mt; mt->SetSingleMethod(MyFunction, nullptr); mt->SetNumberOfThreads(NumThreads); mt->SingleMethodExecute(); mt->SetSingleMethod(MyFunction2, nullptr); mt->SingleMethodExecute(); mt->SetSingleMethod(MyFunction3, nullptr); mt->SingleMethodExecute(); // Making sure that atomic incr returned unique // values each time. We expect all numbers from // 1 to Target to be 2. if (Values32[0] != 0) { std::cout << "Expecting Values32[0] to be 0. Got " << Values32[0] << std::endl; return 1; } if (Values64[0] != 0) { std::cout << "Expecting Values64[0] to be 0. Got " << Values64[0] << std::endl; return 1; } for (int i = 1; i <= Target; i++) { if (Values32[i] != 2) { std::cout << "Expecting Values32[" << i << "] to be 2. Got " << Values32[i] << std::endl; return 1; } if (Values64[i] != 2) { std::cout << "Expecting Values64[" << i << "] to be 2. Got " << Values64[i] << std::endl; return 1; } } vtkMTimeType *from = MTimeValues, *to = MTimeValues + Target; std::sort(from, to); if (std::unique(from, to) != to) { std::cout << "Found duplicate MTime Values" << std::endl; return 1; } mt->SetSingleMethod(MyFunction4, nullptr); mt->SingleMethodExecute(); #ifdef SHOW_DIFFERENCE std::cout << Total << " " << TotalAtomic.load() << std::endl; std::cout << Total64 << " " << TotalAtomic64.load() << std::endl; #endif if (TotalAtomic.load() != Target) { return 1; } if (TotalAtomic64.load() != Target) { return 1; } return 0; }