6

コードでa を使用しstd::atomic<std::shared_ptr>て、shared_ptr をアトミックに更新できるようにしたいのですが、shared_ptr にアクセスするときに問題があります。アトミックの load() メソッドは、shared_ptr の ref-count を減らしているように見えるため、割り当てを解除しないとオブジェクトを実際に使用できません。

これは、問題を示す簡略化されたコードです...

typedef shared_ptr<MyClass> MyClassPtr;
typedef atomic<MyClassPtr> MyClassAtomicPtr;

// 1.
MyClassPtr ptr( new MyClass() );
printf("1. use_count=%d\n", ptr.use_count());

// 2. 
MyClassAtomicPtr atomicPointer(ptr);
printf("2. use_count=%d\n", ptr.use_count());

// 3.
{
    MyClassPtr p = atomicPointer.load();
    printf("3a. use_count=%d\n", ptr.use_count());
}
printf("3b. use_count=%d\n", ptr.use_count());

// 4.
{
    MyClassPtr p = atomicPointer.load();
    printf("4a. use_count=%d\n", ptr.use_count());
}
printf("4b. use_count=%d\n", ptr.use_count());

これの出力は次のとおりです。

1. use_count=1
2. use_count=2
3a. use_count=2
3b. use_count=1
4a. use_count=1
4b. use_count=-572662307

手順 1 と 2 は理解していますが、手順 3 では、shared_ptr への割り当てによって ref-count が 3 に増加し、範囲外になると ref-count が 2 に戻ると予想されます。しかし、実際、割り当てられたときは 2 のままで、shared_ptr が範囲外になると 1 に減少します。同様に、手順 4 では、ref-count がゼロになり、オブジェクトが削除されます。

私の質問は、アトミックによって管理されている shared_ptr を破棄せずにアクセスして使用するにはどうすればよいですか?

(私は Visual Studio 2012 バージョン 11.0.50727.1 RTMREL でコンパイルしていました)

4

4 に答える 4

8

std::shared_ptr<T>のテンプレート引数の型として使用することはできませんstd::atomic<T>。「テンプレート引数 T の型は自明にコピー可能でなければならない。」(§29.5 1 in N3290)std::shared_ptr<T>は自明にコピー可能ではありません。

どうやら、あなたの例std::memcpy(またはそのようなもの)では、をコピーするために使用されstd::shared_ptr、その後デストラクタが呼び出されます。これが、参照カウントが減少する理由です。最後のステップで、オブジェクトが削除されます。

解決策は、 を使用してstd::mutexを保護することstd::shared_ptrです。

于 2012-11-04T10:16:03.183 に答える
5

共有ポインターをアトミックにロードおよびストアする標準的な方法は、§20.7.2.5[util.smartptr.shared.atomic] の関数を使用することだと思います。clang の libc++ だけがそれらをサポートしているようです:

template<class T> bool atomic_is_lock_free(const shared_ptr<T>* p);
template<class T> shared_ptr<T> atomic_load(const shared_ptr<T>* p);
template<class T> shared_ptr<T> atomic_load_explicit(const shared_ptr<T>* p, memory_order mo);
template<class T> void atomic_store(shared_ptr<T>* p, shared_ptr<T> r);
template<class T> void atomic_store_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);
template<class T> shared_ptr<T> atomic_exchange(shared_ptr<T>* p, shared_ptr<T> r);
template<class T> shared_ptr<T> atomic_exchange_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);
template<class T> bool atomic_compare_exchange_weak(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);
template<class T> bool atomic_compare_exchange_strong(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);
template<class T> bool atomic_compare_exchange_weak_explicit(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w, memory_order success, memory_order failure);
template<class T> bool atomic_compare_exchange_strong_explicit(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w, memory_order success, memory_order failure);

したがって、コードは次のように記述できます。

auto ptr = std::make_shared<MyClass>();
printf("1. use_count=%d\n", ptr.use_count());

{
    auto p = std::atomic_load(&ptr);
    printf("3a. use_count=%d\n", ptr.use_count());
}

printf("3b. use_count=%d\n", ptr.use_count());

{
    auto p = std::atomic_load(&ptr);
    printf("3a. use_count=%d\n", ptr.use_count());
}

printf("4b. use_count=%d\n", ptr.use_count());

しかし、MSDN にリストされているそのようなサポートを見つけることができないので、最善の方法はミューテックスを使用することです。(実際には、libc++ でのこれらの関数の実装もミューテックスを使用します。)

于 2012-11-04T10:26:02.307 に答える