-edit-我不能尝试ATM,但今晚。我想也许一个typedef可以用来保存mut,可以用来声明一个var。但我最初的想法是typedef不适合模板,所以我今晚要检查(现在,上课)
我正在查看this piece of code shown below,我想知道如何在不使用定义的情况下实现。
由于我无法编译代码(我当前没有安装任何互斥/多线程库),我只需查看代码并进行思考。
似乎可以通过继承模板类来完全实现PROTECTED_WITH
。问题现在是PROTECTED_MEMBER
。它使用带##的名称来创建变量。这不是一个大问题,因为我们创建了一个类,它使用()
运算符来保存变量,使其显示为函数。但请访问is_held()
问题,因为我不想传递this
或mut_
。
我的直觉开箱即用,认为可以在没有定义的情况下解决这个问题,并且不会将每个变量传递给函数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 );
};
答案 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->member
(object
不是是指针)执行互斥锁断言。
这比说的更容易:
// 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;
};