制作C++;a类监视器(在并发意义上) 我想确保每次只能有一个线程运行我的C++类方法。换句话说,使类的行为像一个

制作C++;a类监视器(在并发意义上) 我想确保每次只能有一个线程运行我的C++类方法。换句话说,使类的行为像一个,c++,multithreading,templates,boost,concurrency,C++,Multithreading,Templates,Boost,Concurrency,是否有一种模式、模板化的方法来实现这一点,或者我可以使用一些Boost类?因为到目前为止,我唯一的想法是添加一个Critical Section成员,并在每个方法开始时获取它,然后在结束时发布它(当然,使用RAII)。但这似乎非常多余,我不能将其重新用于其他类。首先创建通用监视器类。使用C++11的强大功能,您可以做到如下简单: template <class F> struct FunctionType; template <class R, class Object, cl

是否有一种模式、模板化的方法来实现这一点,或者我可以使用一些Boost类?因为到目前为止,我唯一的想法是添加一个Critical Section成员,并在每个方法开始时获取它,然后在结束时发布它(当然,使用RAII)。但这似乎非常多余,我不能将其重新用于其他类。

首先创建通用监视器类。使用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 {};
};
正如您所看到的,有时您需要显式声明要调用的成员函数-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 {};
};
模板
结构函数类型;
模板
结构函数类型{
类型def R return_type;
};
模板
结构函数类型{
类型def R return_type;
};
模板
结构函数类型{
类型def R return_type;
};
模板
结构函数类型{
类型def R return_type;
};
模板
结构函数类型{
类型def R return_type;
};
模板
结构函数类型{
类型def R return_type;
};
模板
班长{
公众:
typedef Object_uobject_utype;
模板
typename FunctionType::返回类型操作(常量F&F)
{
临界截面;
返回(object.*f)();
}
模板
类型名称FunctionType::返回类型操作(常量F&F)常量
{
临界截面;
返回(object.*f)();
}
模板
typename FunctionType::返回类型操作(常量F&F,Arg1 Arg1)
{
临界截面;
返回(object.*f)(arg1);
}
模板
typename FunctionType::返回类型操作(常量F&F,Arg1 Arg1)常量
{
临界截面;
返回(object.*f)(arg1);
}
模板
typename FunctionType::返回类型操作(常量F&F、Arg1 Arg1、Arg2 Arg2)
{
临界截面;
返回(object.*f)(arg1、arg2);
}
模板
typename FunctionType::返回类型操作(常量F&F、Arg1 Arg1、Arg2 Arg2)常量
{
临界截面;
返回(object.*f)(arg1、arg2);
}
私人:
对象类型对象;
类临界_段{};
};

<代码> > p>您可以通过使用“代码>操作程序> >代码>和现代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;
};

我很难想象用更少的代码来做这件事。建议的解决方案所需的代码是类(互斥体成员)的一行代码加上每个函数的一行代码。我认为如果没有特定的语言支持,它不会变小。这是你的问题吗?如果是这样,答案是“C++不支持制作监视器的语言”。)你为什么不使用互斥锁呢,它是广泛可用的。发明你自己的同步原语有一个糟糕的byting诀窍。请看,如果这不够明显的话。:-]这是一个非常优雅的解决方案;唯一的缺点是它需要可变模板支持,VC++仍然缺少。@ DaRooRAMAMOS曾经一度没有任何可变模板;您可以使用重写的方法:
操作
与0,1,2,3。。。参数,而不仅仅是一个具有任意数量参数的
操作
。假设没有人使用超过10个参数,那么实现它是可能的——尽管比可变模板更麻烦……这是一个非常简洁的解决方案。我想你不能推荐一本书或一篇文章来解释变量模板的使用?我发现struct FunctionType很难理解(尤其是对象::*bit。)@TomDavies:这个解决方案背后有三个方面:可变模板;指向成员函数的指针:;和函数类型作为模板参数:。。。我不推荐任何书籍,因为我只是使用C++标准和互联网搜索,如果我需要一些信息,所以也许搜索,如果你没有找到有用的答案,请为这一主题好的书籍…我同情任何非C++程序员随机地在这个问题上。我发现很难相信,<代码> theReaveVeCeope> PuxFiBeBuSE(0);即使在内部也可以工作,我们调用了两次
operator->
,这让我觉得它应该是这样工作的:
threadSafeVector->->->push_back(0)。第一个
threadSafeVector->
返回一个监视器帮助器,然后第二个
->
调用此监视器帮助器上的操作符>。另外,我想知道为什么不在
monitor::operator->
中使用lock\u guard/scope\u guard并从那里返回一个
&m\u cl
。你是否引入了一个额外的结构?@ PrANAVK,C++中的箭头操作符有特殊的语义,允许在前一个调用的返回类型是这个答案使用的指针时重复应用。有关详细信息,请参见示例。至于第二点,我们需要在函数调用期间保持一个锁,这是特殊的
monitor\u helper
struct的生命周期。这在普通锁中是不可能的。感谢您提供向下钻取行为的链接。我不知道这件事。至于第二部分,将
lock\u-guard
作为
monitor::operator->
的第一行将执行您所说的操作-在函数调用期间保持一个锁。@pranavk。不,不会的。试试看-设置一个调试器,并在
锁\u-guard
的析构函数和函数调用中放置一个断点。它将在返回指针并在调用函数之前解除锁定所需的时间。这使用了一个事实,即在函数调用(然后解锁锁)之后,在完整表达式的末尾销毁临时对象。
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;
};
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;