これは確認の質問です。私が詳細を正しく取得していることを確認するために、—言語弁護士を歓迎します。`std :: shared_ptr`のコピーコンストラクタは` reset() `に対してアトミックですか?
std::shared_ptr
を次のコードに使用できることを知りたいので、atomic_shared_ptr
と書き直す必要はありません。この例は単純化されているが、shared_ptr
の(* 1)とreset()
の呼び出し(* 2)の間の単一のインスタンスexample
内の可能な競合状態である。
p
のプレーンポインタはここでは機能しません。テストとsome_predicate
への呼び出しの間にp
がnullになると、nullポインタを間接的に使用しています。これが最初にshared_ptr
を使用する理由です。私は実際に競争状態を解決していることを確認したいだけで、単に他の場所に移動するだけではありません。
(それは質問のポイントではないですが、このコードは一見違って見えるかもしれません。T
の動作は冪等である。p
はその仕事を終えた後は、それはもはや必要ではないです。)
template< class T >
class example
{
shared_ptr<T> p ;
public:
example()
: p(make_shared(T()))
{}
void f()
{
shared_ptr<T> p_transient(p) ; // *1
if (p_transient && p_transient -> some_predicate())
{
p.reset() ; // *2
}
}
};
(* 1)と(* 2)が同時に実行されたとします。私はレースの2つの可能な結果を考えることができます。 (コードは、これら2例それぞれで正しいです。)私の質問は、これらがのみ例であるかどうかをされています
- コピーが
reset
前に有効になりますので、p_transient
は生きているT
のメンバーのインスタンスを保持します。f
が返ったときに、スレッド* 1で実行されます。 reset
がコピーの前に効力を発するので、p_transient
は空に初期化されます(T
の冪等が有効になります)。デリータは、スレッド* 2で動作し、reset
が返されます。
私はここで何も得られていないと感じることができないので、質問を書くことにしました。私が行方不明のものは何ですか?
P.S.ここに私が欠けていたものがあります。 shared_ptr
は特別ではありません。どういうわけか、おそらく前にスマートポインタ(あまりにも多くの時間)を実装したからかもしれないと思っていました。共有ポインタは、特に弱いポインタがある場合は、(隠された)共有状態のためのmutex保護が必要です。私は保護がオブジェクト全体を包含していなければならないと考えましたが、そうではありません。
標準への参照のためのレスポンダーに感謝します。データ競合が未定義の動作になるという一般的なルールは、1.10/27 "マルチスレッド実行とデータ競合[intro.multithread]"です。特に、このような状況で事後条件が違反する可能性があることを意味します。
私は一般的なケースに精通しています。問題は 'std :: shared_ptr'が提供する特定の保証についてです。 – eh9
@ eh9 ahh。 'std :: shared_ptr'は保証を提供しないので、私は一般的なケースに行きました。 2.7.2.2第4節では、shared_ptr( "メンバー関数はshared_ptr' ...オブジェクトそのものだけを参照し、それらが参照するオブジェクトにはアクセスして変更しなければなりません)でデータ競争をどのように扱うべきかを述べています")、 'reset'は20.7.2.2.4のオブジェクト。 –
引用されたブログエントリは便利でした。ありがとう。 – eh9