使用护罩切换静音锁
Toggling mutex lock using guard
如何重构以下代码使用推荐的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
}
相关文章:
- 没有找到相关文章