2016-03-27 3 views
2

私は、mutexでアクセス制御されているオブジェクトをコンテナに持っています。私はしばしばのような何かを:リソースにアクセスするscoped_lockのエレガントなパターン?

rsrc *r; 
{ 
    scoped_lock l(mtx); 
    r = container.pop(); 
} 
// ... use r 

(私は、例外の後にクリーンアップすることを確認するなどscoped_lockを使用)しかし、私は(明示的な制御構造の一部ではありません{...}ブロックを好きではありませんscoped_lockのスコープを作成するためにしか存在しません)、rのヌル初期化と、{...}ブロックでの(おそらく特定ではない)割り当てが好きではありません。

私はこのような何か行うことができます。

inline rsrc *locked_pop(mutex &mtx, container &c) { scoped_lock l(mtx); return c.pop(); } 

とし、その後

OKですが、私は私が同じ(または異なる)コンテナからいくつかの項目を取得する必要がある場合があります
rsrc *r = locked_pop(mtx, container); 

、同じロックの下で

これを行うためのエレガントで一般的な方法をご存じですか? (これは特にBoostの質問ではありませんが、私はこれらのライブラリを使っていますので、Boost-ismは問題ありません)

+0

おそらく、 'struct'を返すでしょう。 – Galik

答えて

0

ありません。リソースをロックし、それぞれの単一の命令でロックするのを避けたい場合。あなたの質問に示されているように、リソースへのローカルアクセスが最適です。

+0

ありがとうございます。周りを見回すと、scoped_lock_varで.unlock()を呼び出すサンプルコードが表示されます。それが有効であれば(私はまだ確信しています)、問題がより簡単になります.scoped_lockを使用してクリーンアップを行いたいのですが、ロックされたセクションを短くするために余分なスコープを必要としません。もし私が手品をした後にロックを解除できれば、*と*のスコープからの終了は二重ロック解除されません(または他の何かが醜い)。それが私の解決です。 –

0

scoped_lockには、scoped_lockの破棄に先立ってロック解除を許可するunlock()関数があります(私は〜scoped_lock()がロックを解除する唯一の方法だとは思っていませんでした。 scoped_lockerが有効範囲外になったときにダブルロックを解除します)。あなたが前にスコープの最後に()のロックを解除することができますので、これは私のために十分なエレガントです:

void consume_resource(locked_container &c) { 
    scoped_lock l(c.mtx); 
    rsrc *r1 = c.pop(); 
    rsrc *r2 = c.pop(); 
    l.unlock(); 
    // CONTAINER NOT LOCKED ANY MORE, DON'T FIDDLE WITH IT (even to check empty(), etc.) 
    // use resources pulled from container 
} 
1
std::tuple<resource_a, resource_b> lock_and_pop(std::mutex& m, container& c) 
{ 
    std::lock_guard<std::mutex> lock(m); 
    auto& top = container.front(); 
    auto result = std::make_tuple(std::move(top.res_a), std::move(top.res_b)); 
    container.pop_front(); 
    return result;  
} 
+0

私は知らなかったstd :: tupleをありがとう。 ( "構造体を返す"アイデアは問題ありませんが、返すことのできる各セットの構造体をコーディングするのは面倒です)。タプル<>とscoped_lock :: unlock()の間に、私はすべて設定されています! –

1

あなたはラムダを使用することができます。同じように使用

template<class F> 
decltype(auto) while_locked(mutex& m,F&&f){ 
    auto lock = scoped_lock(m); 
    return std::forward<F>(f); 
} 

:今

auto* r = while_locked(mtx, [&]{return container.pop();}); 

、私はロックされたデータに私のロックを結合好き。だから私はread(F&&)constwrite(F&&)const-> constを公開するthread_safe<T>を書きました。

彼らの署名が(T->U)[T]T包まれるタイプ[T]->(T->U)->Uのものであるが、渡されたFあり、そしてUは何Fリターンです。

読み取りは、読み取りロックを取得し、書き込みロックを書き込み、->は、を返しているオーバーロードされた->演算子を持つ読み取りロック保持オブジェクトを返します。

また、mutexでorseringを使用して複数のアクセスを処理することもできます。

その後、我々が得る:滑らかなの一種である

auto* r = container.write([](auto&&container){return container.pop_back();}); 

トリックは、a->bが非ポインタ型の場合に(a.operator->())->bと定義されているという事実に依存しています。したがって、ロックを保持している一時的な一時的な値を返すことができます。一時的にポインタを返すのはoperator->です。

これにより、bool b = container->empty()がシームレスに読み取りロックされ、emptyの値が読み取られ、読み取られ、読み取りロックが解除されます。

関連する問題