問題は次のとおりです。
indexとdataの2つの部分を持つPODオブジェクトがあるとします。インデックスのみの等価性をチェックする条件で、アトミックな条件付き交換操作を実行したいと思います。
このようなもの:
struct Data { size_t m_index; char m_data; };
std::atomic<Data> dd; // some initialization
Data zz; // some initialization
// so I want something like this
dd.exchange_if_equals<&Data::m_index>(10,zz);
したがって、これは一種の「部分的-比較-および-完全-スワップ」操作です。たぶん、これにはData::m_index
。
明らかにstd::atomic
はこれをサポートしていませんが、自分で実装することはできますか、またはこれをサポートする別のライブラリがあるでしょうか?
atomic
の代わりにstd::mutex
を使用する場合は、ミューテックスを独自のアトミックのようなラッパーに入れることができます。
これがどのように見えるかの始まりです:
#include <iostream>
#include <type_traits>
#include <mutex>
template<typename T>
class myatomic {
public:
static_assert(
// std::is_trivially_copyable_v<T> && // used in std::atomic, not needed here
std::is_copy_constructible_v<T> &&
std::is_move_constructible_v<T> &&
std::is_copy_assignable_v<T> &&
std::is_move_assignable_v<T>, "unsupported type");
using value_type = T;
myatomic() : data{} {}
explicit myatomic(const T& v) : data{v} {}
myatomic(const myatomic& rhs) : myatomic(rhs.load()) {}
myatomic& operator=(const myatomic& rhs) {
std::scoped_lock lock(mtx, rhs.mtx);
data = rhs.data;
return *this;
}
T load() const {
const std::lock_guard<std::mutex> lock(mtx);
return data;
}
operator T() const {
return load();
}
void store(const T& v) {
const std::lock_guard<std::mutex> lock(mtx);
data = v;
}
myatomic& operator=(const T& v) {
store(v);
return *this;
}
// partial compare and full swap
template<typename Mptr, typename V>
bool exchange_if_equals(Mptr mvar, V mval, const T& oval) {
const std::lock_guard<std::mutex> lock(mtx);
if(data.*mvar == mval) {
data = oval;
return true;
}
return false;
}
template<typename Mptr>
auto get(Mptr mvar) const {
const std::lock_guard<std::mutex> lock(mtx);
return data.*mvar;
}
template<typename Mptr, typename V>
void set(Mptr mvar, const V& v) {
const std::lock_guard<std::mutex> lock(mtx);
data.*mvar = v;
}
private:
mutable std::mutex mtx;
T data;
};
struct Data {
size_t m_index;
char m_data;
};
int main() {
Data orig{10, 'a'};
Data zz; // some initialization
myatomic<Data> dd(orig);
dd.exchange_if_equals(&Data::m_index, 10U, zz);
std::cout << dd.get(&Data::m_index);
}