web-dev-qa-db-ja.com

boost shared_ptr <XXX>スレッドは安全ですか?

_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

Thread_AnowResourceが最新であることを気にしない場合、コードのこの部分に問題がありますか?

つまり、Thread_Bが完全にSetResource()しない場合、Thread_AGetResource()によって間違ったスマートポイントを取得しますか?

Q2

スレッドセーフとはどういう意味ですか?

リソースが最新であるかどうかを気にしない場合、nowResourceが解放されたときに_shared_ptr<CResource> nowResource_はプログラムをクラッシュさせますか、それとも問題によって_shared_ptr<CResource>_が破壊されますか?

32
user25749

ブーストから ドキュメント

shared_ptrオブジェクトは、組み込み型と同じレベルのスレッドセーフを提供します。 shared_ptrインスタンスは、複数のスレッドによって同時に「読み取り」(const操作のみを使用してアクセス)できます。 Differentshared_ptrインスタンスは、複数のスレッドによって同時に「書き込み」(operator=などの可変操作を使用してアクセスまたはリセット)できます(これらのインスタンスがコピーであり、その下で同じ参照カウントを共有している場合でも。)

その他の同時アクセスでは、未定義の動作が発生します。

したがって、m_resの読み取りと書き込みを同時に使用するため、使用は安全ではありません。 ブーストドキュメントの例3もこれを示しています。

SetResource/GetResourcem_resへのアクセスを保護する別の mutex を使用する必要があります。

31
sth

_boost::shared_ptr<>_は、一定レベルのスレッドセーフを提供します。参照カウントはスレッドセーフな方法で操作されます(スレッドサポートを無効にするようにブーストを構成しない限り)。

したがって、_shared_ptr_をコピーすると、ref_countが正しく維持されます。複数のスレッドで安全に実行できないのは、実際の_shared_ptr_オブジェクトインスタンス自体を複数のスレッドから変更することです(複数のスレッドからreset()を呼び出すなど)。したがって、使用法は安全ではありません。複数のスレッドで実際の_shared_ptr_インスタンスを変更しているので、独自の保護が必要になります。

私のコードでは、_shared_ptr_は通常、ローカルまたは値によって渡されるパラメーターであるため、問題はありません。あるスレッドから別のスレッドにそれらを取得する私は通常、スレッドセーフキューを使用します。

もちろん、これはいずれも、_shared_ptr_が指すオブジェクトにアクセスする際のスレッドセーフに対応していません。これもあなた次第です。

40
Michael Burr

そうですね、tr1 :: shared_ptr(boostに基づく)のドキュメントは別の話をしています。これは、リソース管理がスレッドセーフであるのに対し、リソースへのアクセスはそうではないことを意味します。

「...

スレッドセーフ

C++ 0xのみの機能は、右辺値参照/移動サポート、アロケーターサポート、エイリアシングコンストラクター、make_sharedおよびallocate_sharedです。さらに、auto_ptrパラメーターを受け取るコンストラクターはC++ 0xモードでは非推奨になりました。

Boostshared_ptrドキュメントのスレッドセーフセクションには「shared_ptrオブジェクトは組み込み型と同じレベルのスレッドセーフを提供する」と書かれています。実装では、それらのインスタンスが参照カウントを共有している場合でも、個別のshared_ptrインスタンスへの同時更新が正しいことを確認する必要があります。

shared_ptr a(new A); shared_ptr b(a);

//スレッド1 //スレッド2

設定されています(); b.reset();

動的に割り当てられたオブジェクトは、スレッドの1つだけで破棄する必要があります。弱い参照は物事をさらに面白くします。 shared_ptrの実装に使用される共有状態は、ユーザーに対して透過的である必要があり、不変条件は常に保持される必要があります。共有状態の重要な部分は、強参照数と弱参照数です。これらの更新はアトミックであり、管理対象リソースの正しいクリーンアップを確実にするためにすべてのスレッドに表示される必要があります(つまり、shared_ptrの仕事です!)マルチプロセッサシステムでは、参照カウントの更新と破棄のためにメモリ同期が必要になる場合があります管理対象リソースの一部はレースフリーです。

...」

http://gcc.gnu.org/onlinedocs/libstdc++/manual/memory.html#std.util.memory.shared_ptr を参照してください。

3
YoavT

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
1
xpfans