[英]Elegant pattern for scoped_lock to access resource?
我在使用互斥鎖進行訪問控制的容器中有對象。 我經常做這樣的事情:
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( ); }
進而
rsrc *r = locked_pop( mtx, container );
沒關系,但我有一些情況,我需要在同一個鎖下從相同(或不同)容器中獲取多個項目。
你知道一種優雅的、通用的方法嗎? (這不是一個專門的 Boost 問題,但我正在使用這些庫,所以 Boost-ism 就可以了。)
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;
}
您可以使用 lambda。
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( );});
現在,我喜歡將我的鎖綁定到我鎖定的數據上。 所以我寫了thread_safe<T>
它公開read(F&&)const
和write(F&&)const
和-> const
。
它們的簽名是[T]->(T->U)->U
,其中[T]
是包裝的T
, (T->U)
是傳入的F
,而U
是F
返回的。
Read 獲得一個讀鎖,寫一個寫鎖,然后->
返回一個讀鎖持有對象,重載->
運算符返回T const*
。
我們還可以通過互斥鎖上的 orsering 來處理多路訪問。
然后我們得到:
auto* r = container.write([](auto&&container){return container.pop_back();});
這有點光滑。
->
技巧依賴於a->b
被定義為(a.operator->())->b
對於非指針類型的事實。 所以我們可以返回一個持有鎖的臨時對象,然后有一個operator->
返回指針。
這讓我們可以做bool b = container->empty()
,它無縫地做一個讀鎖,讀取empty
的值,存儲它,然后解鎖讀鎖。
空無一人。 如果您想鎖定資源並避免在每條指令中鎖定它。 最好的是本地訪問資源,如您的問題所示。
我沒有意識到 scoped_lock 有一個 unlock() 函數,它允許在破壞 scoped_lock 之前解鎖(我認為 ~scoped_lock() 是解鎖的唯一方法,任何其他 unlock() 都會導致雙重解鎖,當scoped_locker 超出了范圍)。 由於您可以在范圍結束之前 unlock() ,這對我來說已經足夠優雅了:
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
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.