boost::scoped_lock RAII 行为
boost::scoped_lock RAII behaviour
从一个容器class,我想lock
一个boost::mutex
的向量,每个容器都属于一个Controlled 实例(奇怪的代码设计,但仅用于 MWE)。
// std::vector<Controlled*> _vData;
void Container::main_method()
{
for (int i=0; i<_vData.size(); i++)
{
boost::mutex::scoped_lock my_lock(_vData.at(i)->_mutex);
this->processing(i);
}
// precondition for post_processing(): all processing() calls done
for (int i=0; i<_vData.size(); i++)
{
boost::mutex::scoped_lock my_lock(_vData.at(i)->_mutex);
this->post_processing(i);
}
}
但是由于 processing
是 cpu-bound 并且同时从其他地方修改了 Controlled 对象,我想简单地做一个在main_method
开头循环scoped_lock
,为了锁定everything和asap,比如
void Container::desired_main_method()
{
for (int i=0; i<_vData.size(); i++)
{
boost::mutex::scoped_lock my_lock(_vData.at(i)->_mutex);
}
// locks destroyed here, aren't they ?
for (int i=0; i<_vData.size(); i++)
{
this->processing(i);
}
for (int i=0; i<_vData.size(); i++)
{
this->post_processing(i);
}
}
问题是,如果我很好地理解 RAII 惯用语和 scoped_lock
上下文,那么在锁 for
循环结束后,锁将很快超出范围。
我已经尝试 new
在 Container ctor 和 delete
它的 dtor 上的锁数组,但我想这是反对的RAII 习语本身。
我误解了什么,或者我该如何重构整个问题?
假设您的问题是:"how do I use a RAII-like scoped lock for multiple mutexes at the same time?"
然后您可以为多个锁创建自己的 RAII 包装器或使用类似 scope guard.
的东西
(未经测试的伪代码,但希望您能理解。)
template <typename TIterator>
class multiple_lock_guard
{
private:
TIterator _begin, _end;
multiple_lock_guard(TIterator begin, TIterator end)
: _begin{begin}, _end{end}
{
for(auto it = _begin; it != _end; ++it)
{
it->_mutex.lock();
}
}
~multiple_lock_guard()
{
for(auto it = _begin; it != _end; ++it)
{
it->_mutex.unlock();
}
}
};
您可以按如下方式使用:
void Container::desired_main_method()
{
multiple_lock_guard mlg(std::begin(_vData), std::end(_vData));
for(int i = 0; i < _vData.size(); i++)
{
this->processing(i);
}
for(int i = 0; i < _vData.size(); i++)
{
this->post_processing(i);
}
}
下面的怎么样?
void Container::desired_main_method()
{
std::vector<boost::mutex::scoped_lock> locks;
for (int i=0; i<_vData.size(); i++)
{
locks.emplace_back(_vData.at(i)->_mutex);
}
for (int i=0; i<_vData.size(); i++)
{
this->processing(i);
}
for (int i=0; i<_vData.size(); i++)
{
this->post_processing(i);
}
}
您已经可以使用 Boost Thread 的免费函数扩展来自动锁定一组延迟锁:
- http://www.boost.org/doc/libs/1_61_0/doc/html/thread/synchronization.html#thread.synchronization.lock_functions.lock_range
- 遗憾的是,c++17 不提供这种重载 http://en.cppreference.com/w/cpp/thread/lock
#include <boost/thread.hpp>
#include <vector>
struct X {
boost::mutex mutable mx;
};
void foo(std::vector<X> const& xs) {
std::vector<boost::unique_lock<boost::mutex> > locks;
for (auto& x : xs) {
locks.emplace_back(x.mx, boost::defer_lock);
}
boost::lock(locks.begin(), locks.end());
// all locks held
}
int main() {
std::vector<X> xs(10);
foo(xs);
}
从一个容器class,我想lock
一个boost::mutex
的向量,每个容器都属于一个Controlled 实例(奇怪的代码设计,但仅用于 MWE)。
// std::vector<Controlled*> _vData;
void Container::main_method()
{
for (int i=0; i<_vData.size(); i++)
{
boost::mutex::scoped_lock my_lock(_vData.at(i)->_mutex);
this->processing(i);
}
// precondition for post_processing(): all processing() calls done
for (int i=0; i<_vData.size(); i++)
{
boost::mutex::scoped_lock my_lock(_vData.at(i)->_mutex);
this->post_processing(i);
}
}
但是由于 processing
是 cpu-bound 并且同时从其他地方修改了 Controlled 对象,我想简单地做一个在main_method
开头循环scoped_lock
,为了锁定everything和asap,比如
void Container::desired_main_method()
{
for (int i=0; i<_vData.size(); i++)
{
boost::mutex::scoped_lock my_lock(_vData.at(i)->_mutex);
}
// locks destroyed here, aren't they ?
for (int i=0; i<_vData.size(); i++)
{
this->processing(i);
}
for (int i=0; i<_vData.size(); i++)
{
this->post_processing(i);
}
}
问题是,如果我很好地理解 RAII 惯用语和 scoped_lock
上下文,那么在锁 for
循环结束后,锁将很快超出范围。
我已经尝试 new
在 Container ctor 和 delete
它的 dtor 上的锁数组,但我想这是反对的RAII 习语本身。
我误解了什么,或者我该如何重构整个问题?
假设您的问题是:"how do I use a RAII-like scoped lock for multiple mutexes at the same time?"
然后您可以为多个锁创建自己的 RAII 包装器或使用类似 scope guard.
的东西(未经测试的伪代码,但希望您能理解。)
template <typename TIterator>
class multiple_lock_guard
{
private:
TIterator _begin, _end;
multiple_lock_guard(TIterator begin, TIterator end)
: _begin{begin}, _end{end}
{
for(auto it = _begin; it != _end; ++it)
{
it->_mutex.lock();
}
}
~multiple_lock_guard()
{
for(auto it = _begin; it != _end; ++it)
{
it->_mutex.unlock();
}
}
};
您可以按如下方式使用:
void Container::desired_main_method()
{
multiple_lock_guard mlg(std::begin(_vData), std::end(_vData));
for(int i = 0; i < _vData.size(); i++)
{
this->processing(i);
}
for(int i = 0; i < _vData.size(); i++)
{
this->post_processing(i);
}
}
下面的怎么样?
void Container::desired_main_method()
{
std::vector<boost::mutex::scoped_lock> locks;
for (int i=0; i<_vData.size(); i++)
{
locks.emplace_back(_vData.at(i)->_mutex);
}
for (int i=0; i<_vData.size(); i++)
{
this->processing(i);
}
for (int i=0; i<_vData.size(); i++)
{
this->post_processing(i);
}
}
您已经可以使用 Boost Thread 的免费函数扩展来自动锁定一组延迟锁:
- http://www.boost.org/doc/libs/1_61_0/doc/html/thread/synchronization.html#thread.synchronization.lock_functions.lock_range
- 遗憾的是,c++17 不提供这种重载 http://en.cppreference.com/w/cpp/thread/lock
#include <boost/thread.hpp>
#include <vector>
struct X {
boost::mutex mutable mx;
};
void foo(std::vector<X> const& xs) {
std::vector<boost::unique_lock<boost::mutex> > locks;
for (auto& x : xs) {
locks.emplace_back(x.mx, boost::defer_lock);
}
boost::lock(locks.begin(), locks.end());
// all locks held
}
int main() {
std::vector<X> xs(10);
foo(xs);
}