使用护罩切换静音锁

Toggling mutex lock using guard

本文关键字:      更新时间:2023-10-16

如何重构以下代码使用推荐的lock_guards?

bool locked = false;
bool sync() {
    if (locked) {
        mutex.unlock();
    } else {
        mutex.lock();
    }
    locked = !locked;
    return locked;
}

所需的用法模式:

while (sync()) {
    // do safe things
}

基本上,我试图模仿Python的with语句。示例:

from multiprocessing import Lock
with Lock():
    # do safe things

只需创建一个储物柜std::lock_guard<std::mutex> lock(mutex);即可自动在lock的寿命结束时释放。

std::mutex mutex;
....
{
     std::lock_guard<std::mutex> lock(mutex);
     // do do safe things
     // mutex will be released here
}

只需使用范围:

{
    std::lock_guard<std::mutex> lock{mutex};
    // Your operations here
}

如果您真的想具有标头的范围,则C 17的if-与initializer可以轻松地弯曲到该形状中:

if(std::lock_guard<std::mutex> lock{mutex}; true) {
    // Your operations here
}

...然后您可以将其隐藏在一个(周到的)宏中。

最后,随着我对您如何使用该物品的所有责任,这里有一个C 14实现:

template <class T>
struct Lock {
    Lock(T &mtx)
    : guard{mtx} { }
    constexpr operator bool() const { return false; }
    std::lock_guard<T> guard;
};
// Replace the pragmas for a compiler other than Clang or GCC
// so it doesn't complain about the unused variable
#define withLock(mtx) 
    _Pragma("GCC diagnostic push") 
    _Pragma("GCC diagnostic ignored "-Wunused-variable"") 
    if(auto const &_lockGuard = Lock<std::remove_reference_t<decltype(mtx)>>{mtx}); else 
    _Pragma("GCC diagnostic pop")
// ...
withLock(mutex) {
    // Your operations here
}

...但实际上,一个简单的范围正常,不必对代码审阅者进行记录和争论。

您的设计不受锁警卫的支持,并且有充分的理由。您永远不需要切换锁定。共享资源的正确用法模式是,每个访问资源的线程首先通过警卫获取锁,而不是使用资源,而不是存在 - 触发自动锁定。

没有人需要切换锁。

一个完整的示例,说明我通常如何处理它:

#include <mutex>
#include <future>
#include <iostream>
#include <vector>
#include <chrono>
#include <random>
// here is the relevant function
template<class Mutex, class F>
decltype(auto) with_lock(Mutex& mutex, F&& func)
{
    using mutex_type = std::decay_t<Mutex>;
    using lock_type = std::lock_guard<mutex_type>;
    lock_type lock { mutex };
    return func();
}
// here is a test
int main()
{
    std::mutex m;
    std::default_random_engine eng { std::random_device()() };
    std::vector<std::future<void>> futures;
    for (int i = 0 ; i < 100 ; ++i)
    {
        futures.push_back(std::async(std::launch::async, [i, &m, &eng]
        {
            std::uniform_int_distribution<int> dist(10, 100);
            std::this_thread::sleep_for(std::chrono::milliseconds(dist(eng)));
            with_lock(m, [i]
            {
                std::cout << "thread index: " << i << std::endl;
            });
        }));
    }
    for (auto& f : futures)
    {
        f.get();
    }
}

样本输出(请注意,Cout上没有比赛):

thread index: 63
thread index: 62
thread index: 30
thread index: 49
thread index: 25
thread index: 1
thread index: 58
thread index: 33
thread index: 72
thread index: 75
thread index: 11
thread index: 22
thread index: 46
thread index: 41
thread index: 20
thread index: 36
thread index: 37
thread index: 23
thread index: 45
thread index: 82
thread index: 0
thread index: 28
thread index: 88
thread index: 3
thread index: 74
thread index: 84
thread index: 31
thread index: 9
thread index: 34
thread index: 93
thread index: 24
thread index: 98
thread index: 38
thread index: 55
thread index: 43
thread index: 52
thread index: 40
thread index: 69
thread index: 67
thread index: 91
thread index: 89
thread index: 86
thread index: 76
thread index: 21
thread index: 29
thread index: 53
thread index: 81
thread index: 10
thread index: 96
thread index: 68
thread index: 7
thread index: 73
thread index: 78
thread index: 54
thread index: 59
thread index: 83
thread index: 60
thread index: 47
thread index: 19
thread index: 6
thread index: 17
thread index: 56
thread index: 57
thread index: 66
thread index: 70
thread index: 39
thread index: 26
thread index: 13
thread index: 79
thread index: 15
thread index: 5
thread index: 94
thread index: 14
thread index: 77
thread index: 32
thread index: 48
thread index: 87
thread index: 92
thread index: 61
thread index: 80
thread index: 18
thread index: 27
thread index: 12
thread index: 71
thread index: 4
thread index: 2
thread index: 99
thread index: 35
thread index: 50
thread index: 51
thread index: 65
thread index: 64
thread index: 16
thread index: 42
thread index: 90
thread index: 8
thread index: 44
thread index: 85
thread index: 97
thread index: 95

这是一个非常邪恶的,但是工作,hack:

#include <memory>
#include <mutex>
#include <iostream>
#define with(m) for (std::unique_ptr<std::lock_guard<std::mutex>> lock( 
                     new std::lock_guard<std::mutex>(m)); lock; lock.reset())
int main()
{
  std::mutex m;
  with (m)
  {
    std::cout << "got the mutex" << std::endl;
  }
}

with(m)扩展到for循环标头

  • unique_ptr创建一个持有utex的CC_7
  • 在循环条件下,验证指针是非null
  • 在增量部分中,重置指针。

具有执行循环主体的效果,该循环正好遵循with()宏一次,并持有锁定。由于宏观和指针而有点刺,但是比构造while环和切换静音状态的更干净。

如果您有C 14,则可以使用std::make_unique简化宏。如果您可以使用C 17,Quentin的解决方案将更加优雅。

当然,这实际上并不是C 这样做的方法,只是获得一些句法糖的入侵。因此,除非您真的坚持遵循类似python的语法,否则您可以使用标准的C 使用lock_guard的标准方法:

{
  std::lock_guard<std::mutex> lock(my_mutex);
  // Do whatever
}
相关文章:
  • 没有找到相关文章