使C++类成为监视器(在并发意义上)
Making a C++ class a Monitor (in the concurrent sense)
我想确保一次只有一个线程可以运行我的C++类的方法。换句话说,使类的行为类似于监视器。
是否有一种模式,模板化的方式来做到这一点,或者我可以使用一些Boost类?因为到目前为止,我唯一的想法是添加一个关键部分成员,并在每个方法的开头获取它并在结束时释放它(当然使用 RAII)。但这似乎非常多余,我不能将其重用于其他类。
你可以
通过明智地使用operator->
和现代 c++ 来实现这一点,它提供了比以前接受的答案更干净的语法:
template<class T>
class monitor
{
public:
template<typename ...Args>
monitor(Args&&... args) : m_cl(std::forward<Args>(args)...){}
struct monitor_helper
{
monitor_helper(monitor* mon) : m_mon(mon), m_ul(mon->m_lock) {}
T* operator->() { return &m_mon->m_cl;}
monitor* m_mon;
std::unique_lock<std::mutex> m_ul;
};
monitor_helper operator->() { return monitor_helper(this); }
monitor_helper ManuallyLock() { return monitor_helper(this); }
T& GetThreadUnsafeAccess() { return m_cl; }
private:
T m_cl;
std::mutex m_lock;
};
这个想法是使用箭头运算符访问基础对象,但这会返回一个帮助程序对象,该对象锁定然后解锁函数调用周围的互斥锁。然后,通过语言的魔力反复应用operator->
你会得到对底层对象的引用。
用法:
monitor<std::vector<int>> threadSafeVector {5};
threadSafeVector->push_back(0);
threadSafeVector->push_back(1);
threadSafeVector->push_back(2);
// Create a bunch of threads that hammer the vector
std::vector<std::thread> threads;
for(int i=0; i<16; ++i)
{
threads.push_back(std::thread([&]()
{
for(int i=0; i<1024; ++i)
{
threadSafeVector->push_back(i);
}
}));
}
// You can explicitely take a lock then call multiple functions
// without the overhead of a relock each time. The 'lock handle'
// destructor will unlock the lock correctly. This is necessary
// if you want a chain of logically connected operations
{
auto lockedHandle = threadSafeVector.ManuallyLock();
if(!lockedHandle->empty())
{
lockedHandle->pop_back();
lockedHandle->push_back(-3);
}
}
for(auto& t : threads)
{
t.join();
}
// And finally access the underlying object in a raw fashion without a lock
// Use with Caution!
std::vector<int>& rawVector = threadSafeVector.GetThreadUnsafeAccess();
rawVector.push_back(555);
// Should be 16393 (5+3+16*1024+1)
std::cout << threadSafeVector->size() << std::endl;
首先创建通用监视器类。使用 C++11 的幂,您可以像这样简单地做到这一点:
template <class F>
struct FunctionType;
template <class R, class Object, class... Args>
struct FunctionType<R (Object::*)(Args...)> {
typedef R return_type;
};
template <class R, class Object, class... Args>
struct FunctionType<R (Object::*)(Args...) const> {
typedef R return_type;
};
template <class Object_>
class Monitor {
public:
typedef Object_ object_type;
template <class F, class... Args >
typename FunctionType<F>::return_type operation(const F& f, Args... args)
{
critical_section cs;
return (object.*f)(args...);
}
template <class F, class... Args >
typename FunctionType<F>::return_type operation(const F& f, Args... args) const
{
critical_section cs;
return (object.*f)(args...);
}
private:
object_type object;
class critical_section {};
};
当然critical_section
实施取决于您。我推荐POSIX或一些BOOST。
它现在可以使用了:
Monitor<std::vector<int> > v;
v.operation((void (std::vector<int>::*)(const int&)) &std::vector<int>::push_back, 1);
v.operation((void (std::vector<int>::*)(const int&)) &std::vector<int>::push_back, 2);
size = v.operation(&std::vector<int>::size);
std::cout << size << std::endl;
正如你所看到的,有时你需要明确说明你想要调用哪个成员函数 - std::vector<>有多个push_back...
对于仍然不支持可变参数模板的编译器 - 下面没有它的解决方案 - 我有时间最多两个参数 - 这非常不方便 - 如果需要 - 添加具有更多参数的函数:
template <class F>
struct FunctionType;
template <class R, class Object>
struct FunctionType<R (Object::*)()> {
typedef R return_type;
};
template <class R, class Object>
struct FunctionType<R (Object::*)() const> {
typedef R return_type;
};
template <class R, class Object, class Arg1>
struct FunctionType<R (Object::*)(Arg1)> {
typedef R return_type;
};
template <class R, class Object, class Arg1>
struct FunctionType<R (Object::*)(Arg1) const> {
typedef R return_type;
};
template <class R, class Object, class Arg1, class Arg2>
struct FunctionType<R (Object::*)(Arg1,Arg2)> {
typedef R return_type;
};
template <class R, class Object, class Arg1, class Arg2>
struct FunctionType<R (Object::*)(Arg1,Arg2) const> {
typedef R return_type;
};
template <class Object_>
class Monitor {
public:
typedef Object_ object_type;
template <class F>
typename FunctionType<F>::return_type operation(const F& f)
{
critical_section cs;
return (object.*f)();
}
template <class F>
typename FunctionType<F>::return_type operation(const F& f) const
{
critical_section cs;
return (object.*f)();
}
template <class F, class Arg1>
typename FunctionType<F>::return_type operation(const F& f, Arg1 arg1)
{
critical_section cs;
return (object.*f)(arg1);
}
template <class F, class Arg1>
typename FunctionType<F>::return_type operation(const F& f, Arg1 arg1) const
{
critical_section cs;
return (object.*f)(arg1);
}
template <class F, class Arg1, class Arg2>
typename FunctionType<F>::return_type operation(const F& f, Arg1 arg1, Arg2 arg2)
{
critical_section cs;
return (object.*f)(arg1, arg2);
}
template <class F, class Arg1, class Arg2>
typename FunctionType<F>::return_type operation(const F& f, Arg1 arg1, Arg2 arg2) const
{
critical_section cs;
return (object.*f)(arg1, arg2);
}
private:
object_type object;
class critical_section {};
};
相关文章:
- 在 c++ 中,在链表节点上使用括号有什么意义?
- 非模板化函数上的约束表达式有什么意义?
- 在iOS设备上执行并发任务时如何设置正确的线程数?
- 非原子变量上的并发读取
- 在 unix 套接字上调用async_connect有意义吗?
- 在非成员函数上使用删除有什么意义?
- 为什么这个简单的服务器在非常低的并发请求上失败
- 在目标平台上编译 Boost 自己是否有意义
- 如何在Linux上获得C 代码块的时钟刻度?clock()结果没有意义
- 使C++类成为监视器(在并发意义上)
- 在动态内存上操作,重载constmemeber函数有意义吗
- 使用Boost的半并发ICMP ping.Asio在Windows上
- 使用 VS2010 并发运行时消息在非运行时线程上传递类(unbounded_buffer 等)
- 同一服务器上的多个并发 FastCGI 应用程序
- valarray在什么意义上没有混叠
- 具有透明比较器和异构意义上的非唯一元素的映射或集合
- 有多少并发的rtsp流可以可靠地在WAN上传输555个流
- 在原子内容的意义上,从匿名管道原子读取
- 标量在c++类型特征意义上的作用是什么?
- 在Ubuntu中,用C/C++在插孔意义上换行