scoped_lock访问资源的优雅模式?

时间:2016-03-27 17:16:49

标签: c++ design-patterns boost

我在使用互斥锁进行访问控制的容器中有对象。我经常这样做:

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会很好。)

4 个答案:

答案 0 :(得分: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;    
}

答案 1 :(得分:1)

你可以使用lambdas。

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&&)constwrite(F&&)const以及-> const

他们的签名属于[T]->(T->U)->U,其中[T]是包裹的T(T->U)是传入的FUF返回的内容。

读取获取读锁定,写入写锁定,->返回一个读锁定保持对象,其中重载->运算符返回T const*

我们还可以通过对互斥锁进行多次访问来处理。

然后我们得到:

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

有点光滑。

->技巧依赖于a->b被定义为(a.operator->())->b非指针类型的事实。所以我们可以返回一个锁定暂存,然后有一个返回指针的operator->

这允许我们执行bool b = container->empty(),它无缝地执行读锁定,读取empty的值,存储它,然后解锁读锁定。

答案 2 :(得分:0)

没有。如果要锁定资源并避免在每条指令中将其锁定。最好是本地访问资源,如您的问题所示。

答案 3 :(得分:0)

我没有意识到scoped_lock有一个unlock()函数,可以在销毁scoped_lock之前解锁(我以为~scoped_lock()是解锁的唯一方法,而任何其他unlock()都会导致双重 - 当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
}