マルチスレッド検索アルゴリズムのロックレスハッシュテーブルでの次の試みを検討してください(この論文に触発されました)
struct Data
{
uint64_t key;
uint64_t value;
};
struct HashEntry
{
uint64_t key_xor_value;
uint64_t value;
};
void insert_data(Data const& e, HashEntry* h, std::size_t tableOffset)
{
h[tableOffset].key_xor_value = e.key ^ e.value;
h[tableOffset].value = e.value;
}
bool data_is_present(Data const& e, HashEntry const* h, std::size_t tableOffset)
{
auto const tmp_key_xor_value = h[tableOFfset].key_xor_value;
auto const tmp_value = h[tableOffset].value;
return e.key == (tmp_key_xor_value ^ tmp_value);
}
HashEntry
構造体は、構造体の 2 つの 64 ビット ワードの XOR 演算された組み合わせを格納するという考え方ですData
。2 つのスレッドが struct の 2 つの 64 ビット ワードへの読み取り/書き込みをインターリーブした場合HashEntry
、これは読み取りスレッドによって XOR を再度実行し、元の と比較することによって検出できるという考えですkey
。そのため、壊れたハッシュ エントリによって効率が低下する可能性がありますが、デコードされた取得キーが元のキーと一致する場合は、正確性が保証されます。
この論文は、それが次の仮定に基づいていると述べています。
この説明の残りの部分では、64 ビット メモリの読み取り/書き込み操作はアトミックである、つまり 64 ビット値全体が 1 サイクルで読み取り/書き込みされると仮定します。
私の質問は次のとおりです。上記のコードはstd::atomic<uint64_t>
、C++ 11 でスレッドセーフであることが保証されていることを明示的に使用していませんか? または、同時読み取り/書き込みによって個々の 64 ビット ワードが破損する可能性はありますか? 64 ビット プラットフォームでも?これは古い C++98 標準とどう違うのでしょうか?
規格からの引用は大歓迎です。
更新: 「無害な」データ競合に関する Hans Boehmによるこの驚くべき論文に基づいて、噛まれる簡単な方法は、コンパイラが両方の XOR をキャンセルinsert_data()
しdata_is_present()
て常に返すことtrue
です。たとえば、次のようなローカル コード フラグメントが見つかった場合
insert_data(e, h, t);
if (data_is_present(e, h, t)) // optimized to true as if in single-threaded code
read_and_process(e, h, t); // data race if other thread has written