2016-09-21 8 views
1

は、異なるユーザが同じリソースへの同時要求をすることができ、実際のシナリオをモデル化し、以下の単純化されたプログラムを考えてみましょう:同期破壊のstd :: shared_ptrの通じ<T> ::リセット()

#include <thread> 
#include <memory> 
#include <mutex> 
#include <iostream> 

using namespace std; 

struct T { 
    void op() { /* some stuff */ } 
    ~T() noexcept { /* some stuff */ } 
}; 

std::shared_ptr<T> t; 
std::mutex mtx; 
std::weak_ptr<T> w{t}; 
enum action { destroy, op}; 

void request(action a) { 
    if (a == action::destroy) { 
     lock_guard<mutex> lk{mtx}; 
     t.reset(); 
     std::cout << "*t certainly destroyed\n"; 
    } else if (a == action::op) { 
     lock_guard<mutex> lk{mtx}; 
     if (auto l = w.lock()) { 
      l->op(); 
     } 
    } 
} 

int main() { 
    // At some point in time and different points in the program, 
    // two different users make two different concurrent requests 
    std::thread th1{request, destroy}; std::thread th2{request, op}; 

    // .... 
    th2.join(); 
    th1.join(); 
} 

場合、私は求めていないのですプログラムは正式に正しいと思いますが、私はそうだと思いますが、スマートポインタ経由で共有されるの同期破壊の同期破壊を保証するこのアプローチは見たことがありません。私は個人的にそれが罰金であり、有効な使用を持っていると思います。

unique_lockとの古典的な同期や条件変数の変更、さらにはTへの変更(例:アトミックフラグ)の導入を除いて、より洗練された選択肢があるかどうか、他の人が同じと思うかどうかは疑問です。

何とか私がmtxを取り除くことができれば理想的でしょう。

+0

ルーツが見えます。通常の警告では、同時に呼び出されたときに 'T :: op'が正しい必要があることが適用されます。 –

+0

しかし、shared_ptrは決して何にも初期化されていませんか?そして、あなたはファイルレベルの範囲でそれをする必要がありますか? – AndyG

+0

すべての変数は、実際のプログラムで初期化されます。 – Martin

答えて

1

はい、問題ありません。 shared_ptrの参照カウントはアトミックであり、ロックされたコピーはopの持続時間の間スコープ内にとどまるので、opの間にオブジェクトを破棄することはできません。

このケースでは、mutexは実際にTのライフタイムを保護していませんが、シーケンシングはop()と破壊を呼び出します。 op()への複数回の同時呼び出しや、破壊時間が不確定の場合(つまり、最後に実行した後にop()が完了した場合)は、std::shared_ptr<>::reset()std::weak_ptr<>::lock()の両方がスレッドセーフであるため、これを取り除くことができます。

しかし、著者が明らかに、op()の呼び出しがシリアル化されることを意味しているので、私は注意します。

関連する問題