相互排斥的功能相互呼唤

时间:2016-05-13 20:34:05

标签: c++ concurrency mutex

我有两个函数foobar,它们应该互斥,因为它们对相同的数据进行操作。但是foo重复bar的大量代码,因此我想重构foo来调用bar

这是一个问题,因为我不能为这两个函数使用单个互斥锁,因为foo在调用bar时会死锁。因此,而不是互相排斥"我只想要"从不同的线程互相排斥"。

是否有实施此模式?我正在使用C ++,如果我需要像shared_mutex这样的话,我可以使用C ++ 14 / boost。

2 个答案:

答案 0 :(得分:20)

定义私人"解锁"功能和使用来自def flatten(data): flattened = {} for k, v in data.items(): if isinstance(v, dict): flattened.update(flatten(v)) else: flattened[k] = v return flattened foo

的功能
bar

答案 1 :(得分:4)

另一种方式 - 这样做的好处是你可以证明已经锁定了:

void bar_impl(std::unique_lock<std::mutex> lock)
{
   assert(lock.owns_lock());
    // real work
}

void bar()
{
    bar_impl(std::unique_lock<std::mutex>(mx_));
}

void foo()
{
    // stuff
    bar_impl(std::unique_lock<std::mutex>(mx_));
    // more stuff
}

理由:

std::mutex不是(标准要求)可移动,但std::unique_lock<std::mutex>是。#include <mutex> #include <cassert> #include <functional> struct actor { // // public interface // // perform a simple synchronous action void simple_action() { impl_simple_action(take_lock()); } /// perform an action either now or asynchronously in the future /// hander() is called when the action is complete /// handler is a latch - i.e. it will be called exactly once /// @pre an existing handler must not be pending void complex_action(std::function<void()> handler) { impl_complex_action(take_lock(), std::move(handler)); } private: // // private external interface (for callbacks) // void my_callback() { auto lock = take_lock(); assert(!_condition_met); _condition_met = true; impl_condition_met(std::move(lock)); } // private interface using mutex_type = std::mutex; using lock_type = std::unique_lock<mutex_type>; void impl_simple_action(const lock_type& lock) { // assert preconditions assert(lock.owns_lock()); // actions here } void impl_complex_action(lock_type my_lock, std::function<void()> handler) { _handler = std::move(handler); if (_condition_met) { return impl_condition_met(std::move(my_lock)); } else { // initiate some action that will result in my_callback() being called // some time later } } void impl_condition_met(lock_type lock) { assert(lock.owns_lock()); assert(_condition_met); if(_handler) { _condition_met = false; auto copy = std::move(_handler); // unlock here because the callback may call back into our public interface lock.unlock(); copy(); } } auto take_lock() const -> lock_type { return lock_type(_mutex); } mutable mutex_type _mutex; std::function<void()> _handler = {}; bool _condition_met = false; }; void act(actor& a) { a.complex_action([&a]{ // other stuff... // note: calling another public interface function of a // during a handler initiated by a // the unlock() in impl_condition_met() makes this safe. a.simple_action(); }); } 。出于这个原因,我们可以将锁定移动到被调用者并将其返回给调用者(如果需要)。

这使我们能够在调用链的每个阶段证明锁的所有权。

此外,一旦优化者参与进来,所有锁定移动都可能会被优化掉。这给了我们两全其美 - 可证明的所有权和最大的表现。

更完整的例子:

vis