boostshared_ptr<XXX>はスレッドセーフですか?
-
22-08-2019 - |
質問
について質問があります boost::shared_ptr<T>
.
スレッドがたくさんあります。
using namespace boost;
class CResource
{
// xxxxxx
}
class CResourceBase
{
public:
void SetResource(shared_ptr<CResource> res)
{
m_Res = res;
}
shared_ptr<CResource> GetResource()
{
return m_Res;
}
private:
shared_ptr<CResource> m_Res;
}
CResourceBase base;
//----------------------------------------------
// Thread_A:
while (true)
{
//...
shared_ptr<CResource> nowResource = base.GetResource();
nowResource.doSomeThing();
//...
}
// Thread_B:
shared_ptr<CResource> nowResource;
base.SetResource(nowResource);
//...
Q1
もし スレッド_A 気にしないでください nowResource
は最新ですが、コードのこの部分に問題はありますか?
つまり、いつ スレッド_B しないでください SetResource()
完全に、 スレッド_A 間違ったスマートポイントを取得する GetResource()
?
第2四半期
スレッドセーフとはどういう意味ですか?
リソースが最新かどうかを気にしない場合、 shared_ptr<CResource> nowResource
プログラムがクラッシュすると、 nowResource
解放されますか、それとも問題によって破壊されますか shared_ptr<CResource>
?
解決
ブーストから ドキュメンテーション:
shared_ptr
オブジェクトは、組み込みのタイプと同じレベルのスレッド安全を提供します。あshared_ptr
インスタンスは、複数のスレッドで同時に「読み取り」(const操作のみを使用してアクセス)できます。 違うshared_ptr
インスタンスは「書き込み」することができます(などの可変操作を使用してアクセスできますoperator=
またはリセット)複数のスレッドで同時に(これらのインスタンスがコピーである場合でも、同じ参照カウントを下に共有します。)それ以外の同時アクセスでは、未定義の動作が発生します。
したがって、同時の読み取りと書き込みを使用するため、使用は安全ではありません。 m_res
. 例 3 boost のドキュメントにもこれが示されています。
別のものを使用する必要があります ミューテックス へのアクセスを保護するもの m_res
で SetResource
/GetResource
.
他のヒント
boost::shared_ptr<>
一定レベルのスレッド安全性を提供します。参照カウントは、スレッド セーフな方法で操作されます (スレッド サポートを無効にするようにブーストを構成しない限り)。
したがって、コピーできます shared_ptr
ref_count は正しく維持されます。マルチスレッドで安全に実行できないのは、実際のスレッドを変更することです。 shared_ptr
複数のスレッドからのオブジェクト インスタンス自体 (呼び出しなど) reset()
複数のスレッドからアクセスできます)。したがって、あなたの使用法は安全ではありません - 実際の shared_ptr
複数のスレッド内のインスタンス - 独自の保護が必要になります。
私のコードでは、 shared_ptr
は通常、ローカルまたは値によって渡されるパラメータであるため、問題はありません。あるスレッドから別のスレッドにそれらを取得するには、通常、スレッドセーフなキューを使用します。
もちろん、これはどれも、 shared_ptr
-それもあなた次第です。
そうですね、tr1::shared_ptr (ブーストに基づいています) のドキュメントには別の話があり、リソース管理はスレッド セーフであるが、リソースへのアクセスはスレッド セーフではないことが暗示されています。
"...
スレッドの安全性
C++0x のみの機能は次のとおりです。rvalue-ref/move サポート、アロケーター サポート、エイリアス コンストラクター、make_shared および assign_shared。さらに、auto_ptr パラメーターを受け取るコンストラクターは、C++0x モードでは非推奨になりました。
Boost Shared_ptrドキュメントのスレッド安全セクションには、「共有_PTRオブジェクトは、組み込みのタイプと同じレベルのスレッド安全を提供します」と書かれています。実装は、それらのインスタンスがリファレンスカウントを共有する場合でも、Shared_PTRインスタンスを分離する同時の更新が正しいことを確認する必要があります
共有_ptr a(新しいA);共有_ptr b(a);
// スレッド 1 // スレッド 2
設定されています();b.reset();
動的に割り当てられたオブジェクトは、いずれかのスレッドによってのみ破棄される必要があります。弱い参照を使用すると、さらに興味深いことが起こります。shared_ptr の実装に使用される共有状態はユーザーに対して透過的である必要があり、不変条件は常に保持される必要があります。共有状態の重要な部分は、強参照数と弱参照数です。これらの更新はアトミックであり、管理対象リソースの正しいクリーンアップ (結局のところ、shared_ptr の仕事です!) を保証するために、すべてのスレッドに表示される必要があります。 マルチプロセッサ システムでは、参照カウントの更新と破棄を行うために、メモリの同期が必要になる場合があります。の管理リソースには人種がありません。
..."
見るhttp://gcc.gnu.org/onlinedocs/libstdc++/manual/memory.html#std.util.memory.shared_ptr
m_Res スレッドセーフではありません。それは同時読み取り/書き込みであるため、それを保護するためにboost :: atomic_store/load関数が必要です。
//--- Example 3 ---
// thread A
p = p3; // reads p3, writes p
// thread B
p3.reset(); // writes p3; undefined, simultaneous read/write
さらに、クラスには循環参照条件があります。の shared_ptr<CResource> m_Res
のメンバーになることはできません CResourceBase
. 。使用できます weak_ptr
その代わり。