删除此safeguard mutex示例中的定义

时间:2011-06-14 19:11:57

标签: c++ templates mutex

-edit-我不能尝试ATM,但今晚。我想也许一个typedef可以用来保存mut,可以用来声明一个var。但我最初的想法是typedef不适合模板,所以我今晚要检查(现在,上课)

我正在查看this piece of code shown below,我想知道如何在不使用定义的情况下实现。

由于我无法编译代码(我当前没有安装任何互斥/多线程库),我只需查看代码并进行思考。

似乎可以通过继承模板类来完全实现PROTECTED_WITH。问题现在是PROTECTED_MEMBER。它使用带##的名称来创建变量。这不是一个大问题,因为我们创建了一个类,它使用()运算符来保存变量,使其显示为函数。但请访问is_held()问题,因为我不想传递thismut_

我的直觉开箱即用,认为可以在没有定义的情况下解决这个问题,并且不会将每个变量传递给函数ptr或引用。我将允许每个人作弊并使用c ++ 0x功能。

template<typename Mutex>
class TestableMutex {
public:
     void lock()      {  m.lock();  id = this_thread::get_id();  }
     void unlock()    {  id = 0;  m.unlock();  }
     bool try_lock()  {  bool b = m.try_lock();
                 if( b ) id = this_thread::get_id();
                 return b;  }
     bool is_held()    { return id == this_thread::get_id(); }
private:
     Mutex m;
     atomic<thread::id> id;
     // for recursive mutexes, add a count
};

#define PROTECTED_WITH(MutType)  \
     public:    void    lock()        {  mut_.lock();  } \
     public:    bool    try_lock()    {  return mut_.try_lock();  } \
     public:    void    unlock()      {  mut_.unlock();  } \
     private:    TestableMutex<MutType> mut_;
#define PROTECTED_MEMBER(Type,name) \
     public:    Type&   name()        { assert(mut_.is_held()); return name##_; } \
     private:    Type   name##_;

struct MyData {
     PROTECTED_WITH( some_mutex_type );
     PROTECTED_MEMBER( vector<int>, v );
     PROTECTED_MEMBER( Widget*, w );
};

2 个答案:

答案 0 :(得分:1)

#define没有提供任何保护,而只是减少你必须做的打字量(反过来,他们确保所有“受保护”的成员都有适当的代码到位)。

我没有一种方法可以避免必须将检查放入每个getter函数 - 并锁定整个对象,因为它们返回对受保护对象中存储的数据的引用。

但是,如果它们都可以按值返回(或者根本不返回任何内容),那么你可以使用一个使用代理对象锁定所有东西的容器,如下所示(这可能会做得更好,我'我们很快就把它砍成了一起):

#include <iostream>

struct Mutex
{
    void lock()
    {
        std::cout << "Mutex::lock" << std::endl;
    }

    void unlock()
    {
        std::cout << "Mutex::unlock" << std::endl;
    }
};

template <class Object>
class ThreadSafeObject
{
    mutable Mutex  d_mutex;
    Object         d_object;

  public:
    struct Proxy
    {
        mutable Mutex *d_mutex;
        Object        *d_object;

        Proxy(Mutex *mutex, Object *object)
        : d_mutex(mutex)
        , d_object(object)
        {
            d_mutex->lock();
        }

        Proxy(const Proxy& proxy)
        : d_mutex(proxy.d_mutex)
        , d_object(proxy.d_object)
        {
            proxy.d_mutex = NULL;
        }

        ~Proxy()
        {
            if (d_mutex)
            {
                d_mutex->unlock();
            }
        }

        Object *operator->()
        {
            return d_object;
        }
    };

    struct ConstProxy
    {
        mutable Mutex *d_mutex;
        const Object  *d_object;

        ConstProxy(Mutex *mutex, const Object *object)
        : d_mutex(mutex)
        , d_object(object)
        {
            d_mutex->lock();
        }

        ConstProxy(const ConstProxy& proxy)
        : d_mutex(proxy.d_mutex)
        , d_object(proxy.d_object)
        {
            proxy.d_mutex = NULL;
        }

        ~ConstProxy()
        {
            if (d_mutex)
            {
                d_mutex->unlock();
            }
        }

        const Object *operator->() const
        {
            return d_object;
        }
    };

    Proxy operator->()
    {
        return Proxy(&d_mutex, &d_object);
    }

    ConstProxy operator->() const
    {
        return ConstProxy(&d_mutex, &d_object);
    }
};

struct Foo
{
    void foo()
    {
        std::cout << "Foo::foo" << std::endl;
    }
};

int main()
{
    ThreadSafeObject<Foo> myFoo;
    myFoo->foo();
    return 0;
}

使用operator-&gt;()技巧(当operator-&gt;不会重新命名指针类型时,编译器将继续对返回的值调用operator-&gt;直到最终返回常规指针类型< / em>)并提供以下输出:

Mutex::lock
Foo::foo
Mutex::unlock

一般来说,一个需要被多个线程使用的对象不应该像这样暴露它的内部,让它接受参数并使用它的内部值来对它们起作用会更安全。

答案 1 :(得分:1)

您可以使用包含using声明的显式特化来列出受互斥锁保护的对象。然后使用基类通过operator->将访问“传递”给用户,因此object->memberobject 不是是指针)执行互斥锁断言。

这比说的更容易:

// Imagine that the members of this class must be locked by the mutex.
class a : public expose_locked_by_arrow< a > {
protected:
    int i;
    void f();
};

// Declare which members are conditionally locked. Pretty simple and idiomatic.
template<>
struct member_expose< a > : a {
    using a::i;
    using a::f;
};

#include <iostream>

// Access mutex-locked members with ->
int main() {
        a x;
        x->i = 5;
        a const y( x );
        std::cout << y->i << '\n';
}

图书馆代码:

// This template is specialized for each mutex protection client.
template< class >
struct member_expose;

// Base class provides mutex; parameter is derived class (CRTP).
template< class c >
struct expose_locked_by_arrow {
    member_expose< c > *
    operator->() {
        assert ( expose_lock_mutex.is_held() );
        return static_cast< member_expose< c > * >( this );
    }

    member_expose< c > const *
    operator->() const {
        assert ( expose_lock_mutex.is_held() );
        return static_cast< member_expose< c > const * >( this );
    }

    expose_locked_by_arrow( mutex const &m = mutex() )
        : expose_lock_mutex( m ) {}

protected:
    mutex expose_lock_mutex;
};

See it run