[解決済み] std::atomicのロックはどこにありますか?
質問
データ構造に複数の要素がある場合、そのアトミックなバージョンは (常に) ロックフリーであることはできません。 これは、CPU が何らかのロックを使用せずにデータをアトミックに変更できないため、より大きな型に当てはまると聞きました。
たとえば
#include <iostream>
#include <atomic>
struct foo {
double a;
double b;
};
std::atomic<foo> var;
int main()
{
std::cout << var.is_lock_free() << std::endl;
std::cout << sizeof(foo) << std::endl;
std::cout << sizeof(var) << std::endl;
}
という出力があります(Linux/gcc)。
0
16
16
アトミックと
foo
は同じサイズなので、atomicにロックが格納されているとは思えません。
質問なのですが
アトム変数がロックを使用する場合、それはどこに格納され、その変数の複数のインスタンスのために何を意味するのでしょうか?
どのように解決するのですか?
このような質問に答える最も簡単な方法は、一般に、出来上がったアセンブリを見て、そこから判断することです。
次のようにコンパイルします (コンパイラの悪巧みをかわすために、構造体を大きくしました)。
#include <atomic>
struct foo {
double a;
double b;
double c;
double d;
double e;
};
std::atomic<foo> var;
void bar()
{
var.store(foo{1.0,2.0,1.0,2.0,1.0});
}
clang 5.0.0では、-O3のもとで以下のようになります。 godboltで見る
bar(): # @bar()
sub rsp, 40
movaps xmm0, xmmword ptr [rip + .LCPI0_0] # xmm0 = [1.000000e+00,2.000000e+00]
movaps xmmword ptr [rsp], xmm0
movaps xmmword ptr [rsp + 16], xmm0
movabs rax, 4607182418800017408
mov qword ptr [rsp + 32], rax
mov rdx, rsp
mov edi, 40
mov esi, var
mov ecx, 5
call __atomic_store
素晴らしいことに、コンパイラは組込み関数に委ねる (
__atomic_store
) に委譲しているのですが、これでは何が本当に起こっているのかわかりません。しかし、このコンパイラはオープンソースであるため、組込み関数の実装を簡単に見つけることができます。
https://github.com/llvm-mirror/compiler-rt/blob/master/lib/builtins/atomic.c
):
void __atomic_store_c(int size, void *dest, void *src, int model) {
#define LOCK_FREE_ACTION(type) \
__c11_atomic_store((_Atomic(type)*)dest, *(type*)dest, model);\
return;
LOCK_FREE_CASES();
#undef LOCK_FREE_ACTION
Lock *l = lock_for_pointer(dest);
lock(l);
memcpy(dest, src, size);
unlock(l);
}
でマジックが起こるようです。
lock_for_pointer()
にあるようなので、見てみましょう。
static __inline Lock *lock_for_pointer(void *ptr) {
intptr_t hash = (intptr_t)ptr;
// Disregard the lowest 4 bits. We want all values that may be part of the
// same memory operation to hash to the same value and therefore use the same
// lock.
hash >>= 4;
// Use the next bits as the basis for the hash
intptr_t low = hash & SPINLOCK_MASK;
// Now use the high(er) set of bits to perturb the hash, so that we don't
// get collisions from atomic fields in a single object
hash >>= 16;
hash ^= low;
// Return a pointer to the word to use
return locks + (hash & SPINLOCK_MASK);
}
そして、ここからが説明です。アトミックのアドレスは、事前に割り当てられたロックを選択するためのハッシュキーを生成するために使用されます。
関連
-
[解決済み】C++ - 解放されるポインタが割り当てられていないエラー
-
[解決済み] クラスにデフォルトコンストラクタが存在しない。
-
[解決済み】なぜ、サイズ8の初期化されていない値を使用するのでしょうか?
-
[解決済み】デバッグアサーションに失敗しました
-
[解決済み] explicit キーワードの意味は?
-
[解決済み] 文字列の単語を反復処理するにはどうすればよいですか?
-
[解決済み] using namespace std;」はなぜバッドプラクティスだと言われるのですか?
-
[解決済み] アトミック属性と非アトミック属性の違いは何ですか?
-
[解決済み] なぜ、オブジェクトそのものではなく、ポインタを使用しなければならないのですか?
-
[解決済み】C/C++の"-->"演算子とは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】getline()が何らかの入力の後に使用されると動作しない 【重複あり
-
[解決済み】識別子 "string "は未定義?
-
[解決済み】C++ - 解放されるポインタが割り当てられていないエラー
-
[解決済み】C++エラーです。"配列は中括弧で囲まれたイニシャライザーで初期化する必要がある"
-
[解決済み] 非常に基本的なC++プログラムの問題 - バイナリ式への無効なオペランド
-
[解決済み】Visual Studio 2013および2015でC++コンパイラーエラーC2280「削除された関数を参照しようとした」が発生する
-
[解決済み] gdbを使用してもデバッグシンボルが見つからない
-
[解決済み】なぜ、サイズ8の初期化されていない値を使用するのでしょうか?
-
[解決済み] 警告:暗黙の定数変換でのオーバーフロー
-
[解決済み】'std::cout'への未定義の参照