std :: atomic :: is_lock_free()がconstexprと同様に静的でないかどうか誰かに教えてもらえますか?それを非静的および/または非constexprとして持つことは私には意味がありません。
std :: atomic :: is_lock_free()がconstexprと同様に静的でないかどうか誰かに教えてもらえますか?それを非静的および/または非constexprとして持つことは私には意味がありません。
回答:
cppreferenceで説明したように:
std :: atomic_flagを除くすべてのアトミック型は、ロックフリーのアトミックCPU命令を使用するのではなく、ミューテックスまたは他のロック操作を使用して実装できます。アトミックタイプはロックフリーになることもできます。たとえば、特定のアーキテクチャーでアラインされたメモリアクセスのみが自然にアトミックである場合、同じタイプのミスアラインされたオブジェクトはロックを使用する必要があります。
C ++標準では、ロックフリーアトミック操作もアドレスフリーであること、つまり共有メモリを使用するプロセス間の通信に適していることを推奨しています(ただし必須ではありません)。
他の複数の人がstd::is_always_lock_free
述べたように、あなたが本当に探しているものかもしれません。
編集:明確にするために、C ++オブジェクトタイプには、インスタンスのアドレスを2の累乗の特定の倍数([basic.align]
)のみに制限するアライメント値があります。これらの位置合わせ値は、基本型の実装定義であり、型のサイズと同じである必要はありません。また、ハードウェアが実際にサポートできるものよりも厳しい場合もあります。
たとえば、x86は(ほとんど)非境界整列アクセスをサポートしています。ただし、alignof(double) == sizeof(double) == 8
境界整列されていないアクセスには多くの欠点(速度、キャッシング、原子性など)があるため、ほとんどのコンパイラーはx86用です。しかし、たとえば#pragma pack(1) struct X { char a; double b; };
、alignas(1) double x;
「アラインメントされていない」double
s を使用できます。したがって、cppreferenceが「アライメントされたメモリアクセス」について話すとき、それはおそらくハードウェアの型の自然なアライメントの観点からそうであり、そのアライメント要件(UBである)と矛盾する方法でC ++型を使用しません。
詳細は次のとおりです。x86でのアライメントされていないアクセスの成功の実際の影響は何ですか?
以下の@Peter Cordesによる洞察に満ちたコメントもご覧ください。
alignof(double)==4
。しかし、実行時にアライメントをチェックする代わりに、std::atomic<double>
まだ持っていalignof() = 8
ます。アトミックにアンダーアラインされるパックされた構造体を使用すると、ABIが壊れ、サポートされません。(32ビットx86のGCCは、8バイトのオブジェクトを自然に配置することを好みますが、構造体パッキングルールはそれをオーバーライドし、alignof(T)
i386 System V などにのみ基づいています。G++にはatomic<int64_t>
、構造体の内部がアトミックでない可能性があるバグがありましたGCC(C ++ではなくCの場合)にはまだこのバグがあります!)
std::atomic_ref<double>
は、アンダーアラインをdouble
完全に拒否するか、プラットフォーム上で実行時にアラインメントをチェックし、プレーンでdouble
ありint64_t
、自然にアラインされていないことが合法です。(atomic_ref<T>
プレーンとして宣言されたオブジェクトを操作するため、追加の配置を行う機会T
がalignof(T)
ない最小の配置しかありません。)
_Atomic int64_t
currentでコンパイルしたときにの破損を示す純粋なISO C11テストケースgcc -m32
。とにかく、私の要点は、実際のコンパイラーは整列されていないアトミックをサポートしておらず、実行時チェックを(まだ?)していないということです。そうし#pragma pack
ない__attribute__((packed))
と、非原子性につながるだけです。オブジェクトは、それがまだであることを報告しますlock_free
。
is_lock_free()
することです許可の実装は、現在のものは実際に行う方法とは異なる動作します。HWがサポートするアトミック命令を使用するため、またはロックを使用するために、実際のアライメントに基づくランタイムチェックを使用します。
あなたは使うかもしれません std::is_always_lock_free
is_lock_free
実際のシステムに依存し、コンパイル時に決定することはできません。
関連する説明:
アトミックタイプはロックフリーになることもできます。たとえば、特定のアーキテクチャーで整列されたメモリアクセスのみが自然にアトミックである場合、同じタイプの整列されていないオブジェクトはロックを使用する必要があります。
std::numeric_limits<int>::max
アーキテクチャに依存しますが、静的であり、constexpr
です。答えは間違っていないと思いますが、私は推論の最初の部分は購入しません
is_lock_free
は、そのコンパイラでは意味がないことを意味します。
Windows PCにVisual Studio 2019をインストールしましたが、このdevenvにもARMv8コンパイラがあります。ARMv8は非境界整列アクセスを許可しますが、比較とスワップ、ロックされた追加などは、境界整列が義務付けられています。また、ldp
or stp
(32ビットレジスタのロードペアまたはストアペア)を使用した純粋なロード/純粋なストアは、それらが自然にアライメントされている場合にのみアトミックであることが保証されます。
そこで、任意のアトミックポインターに対してis_lock_free()が何を返すかを確認する小さなプログラムを書きました。だからここにコードがあります:
#include <atomic>
#include <cstddef>
using namespace std;
bool isLockFreeAtomic( atomic<uint64_t> *a64 )
{
return a64->is_lock_free();
}
そして、これはisLockFreeAtomicの逆アセンブリです
|?isLockFreeAtomic@@YA_NPAU?$atomic@_K@std@@@Z| PROC
movs r0,#1
bx lr
ENDP
これはreturns true
別名1
です。
この実装はalignof( atomic<int64_t> ) == 8
、すべてatomic<int64_t>
が正しく整列するように使用することを選択します。これにより、すべてのロードとストアで実行時のアライメントチェックが不要になります。
(編集者注:これは一般的です。ほとんどの実際のC ++実装はこのように機能します。これstd::is_always_lock_free
が非常に便利な理由です。通常、これはtrueである型に対してtrueであるためis_lock_free()
です。)
atomic<uint64_t>
を選択するalignof() == 8
ので、実行時にアライメントをチェックする必要はありません。この古いAPIには、そうしないという選択肢がありますが、現在のハードウェアでは、アラインメントを要求するだけの方が理にかなっています(そうでなければ、非原子性などのUB)。int64_t
4バイトアライメントしかない可能性がある32ビットコードでも、atomic<int64_t>
8バイトが必要です。別の回答
alignof
、ハードウェアの「良い」アライメントと同じ基本的なタイプの値を、そして is_lock_free
常になりますtrue
(とそうなりますis_always_lock_free
)。ここのコンパイラはまさにこれを行います。ただし、APIが存在するため、他のコンパイラはさまざまなことを実行できます。
alignof(std::atomic<double>) == 1
、ハードウェアがdouble
4または8バイト境界。コンパイラは、アライメントされていない場合にロックを使用する必要is_lock_free
があります(オブジェクトインスタンスのメモリの場所に応じて、適切なブール値をから返します)。
is_always_lock_free
ますか?