vtk-m/vtkm/cont/internal/AtomicInterfaceExecution.h

83 lines
2.0 KiB
C
Raw Normal View History

//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
2019-04-15 23:24:21 +00:00
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_cont_internal_AtomicInterfaceExecution_h
#define vtk_m_cont_internal_AtomicInterfaceExecution_h
#include <vtkm/Atomic.h>
#include <vtkm/Deprecated.h>
namespace vtkm
{
namespace cont
{
namespace internal
{
template <typename DeviceTag>
struct VTKM_DEPRECATED(1.6, "Use the functions in vtkm/Atomic.h.") AtomicInterfaceExecution
{
using WordTypes = vtkm::AtomicTypesSupported;
using WordTypePreferred = vtkm::AtomicTypePreferred;
template <typename T>
VTKM_EXEC_CONT static T Load(const T* addr)
{
return vtkm::AtomicLoad(addr);
}
template <typename T>
VTKM_EXEC_CONT static void Store(T* addr, T value)
{
vtkm::AtomicStore(addr, value);
}
template <typename T>
VTKM_EXEC_CONT static T Add(T* addr, T arg)
{
return vtkm::AtomicAdd(addr, arg);
}
template <typename T>
VTKM_EXEC_CONT static T Not(T* addr)
{
return vtkm::AtomicNot(addr);
}
template <typename T>
VTKM_EXEC_CONT static T And(T* addr, T mask)
{
return vtkm::AtomicAnd(addr, mask);
}
template <typename T>
VTKM_EXEC_CONT static T Or(T* addr, T mask)
{
return vtkm::AtomicOr(addr, mask);
}
template <typename T>
VTKM_EXEC_CONT static T Xor(T* addr, T mask)
{
return vtkm::AtomicXor(addr, mask);
}
template <typename T>
VTKM_EXEC_CONT static T CompareAndSwap(T* addr, T newWord, T expected)
{
Change interface of atomic compare and swap The old atomic compare and swap operations (`vtkm::AtomicCompareAndSwap` and `vtkm::exec::AtomicArrayExecutionObject::CompareAndSwap`) had an order of arguments that was confusing. The order of the arguments was shared pointer (or index), desired value, expected value. Most people probably assume expected value comes before desired value. And this order conflicts with the order in the `std` methods, GCC atomics, and Kokkos. Change the interface of atomic operations to be patterned off the `std::atomic_compare_exchange` and `std::atomic<T>::compare_exchange` methods. First, these methods have a more intuitive order of parameters (shared pointer, expected, desired). Second, rather than take a value for the expected and return the actual old value, they take a pointer to the expected value (or reference in `AtomicArrayExecutionObject`) and modify this value in the case that it does not match the actual value. This makes it harder to mix up the expected and desired parameters. Also, because the methods return a bool indicating whether the value was changed, there is an additional benefit that compare-exchange loops are implemented easier. For example, consider you want to apply the function `MyOp` on a `sharedValue` atomically. With the old interface, you would have to do something like this. ```cpp T oldValue; T newValue; do { oldValue = *sharedValue; newValue = MyOp(oldValue); } while (vtkm::AtomicCompareAndSwap(sharedValue, newValue, oldValue) != oldValue); ``` With the new interface, this is simplfied to this. ```cpp T oldValue = *sharedValue; while (!vtkm::AtomicCompareExchange(sharedValue, &oldValue, MyOp(oldValue)); ```
2020-09-25 00:02:59 +00:00
vtkm::AtomicCompareExchange(addr, &expected, newWord);
return expected;
}
};
}
}
} // end namespace vtkm::cont::internal
#endif // vtk_m_cont_internal_AtomicInterfaceExecution_h