说我有一个班级A
:
class A {
public:
A();
void fetch_data() { return 1; }
void write_x_data() {
// lock this instance of A
private_function1_which_assumes_locked();
private_function2_which_assumes_locked();
// unlock this instance of A
}
void write_y_data() {
// lock this instance of A
private_function1_which_assumes_locked();
// unlock this instance of A
}
private:
void private_function1_which_assumes_locked();
void private_function2_which_assumes_locked();
};
我想保证永远不会调用private_function*_which_assumed_locked()
,除非A
被锁定。
实现这一目标的最佳方法是什么?我有5个左右需要锁定的公共函数。这些函数从不相互调用,所以我并不担心这些函数会陷入僵局。结合起来,这5个公共函数调用大约15个不同的私有函数,这些函数需要假设对象处于锁定状态。显然,我无法锁定私有函数,因为我会遇到死锁。
假设存在互斥锁和Scopeguards,请随意在合理的高级抽象中提供答案。
在Python中,我可以使用decorators 执行之类的 。
class locked_method(object):
def __init__(self, f):
self.f = f
def __call__(self):
# Do whatever is needed to lock
self.f()
# Do whatever is needed to unlock
class checklocked(object):
def __init__(self, f):
self.f = f
def __call__(self):
# check locked, if not, don't call self.f(),
# and yell at me loudly for screwing up.
self.f()
@locked_method
def func1():
__function_which_assumes_locked()
@checklocked
def __function_which_assumes_locked():
pass
注意:我对Python的方式做得不多,所以如果我的Python错误/愚蠢,请随意评论,但这个问题的重点更多是在C ++中完成此类事情的最佳方法,所以希望Python提供的内容足以让你知道我想做什么。
答案 0 :(得分:4)
您可以使用一个更衣室类,并且要求存在一个以便调用私有函数:
class A
{
public:
void write()
{
Lock l(this);
write(l);
}
private:
void lock();
void unlock();
void write(const Lock &);
class Lock
{
public:
explicit Lock(A *a) : parent(a) {parent->lock();}
~Lock() {parent->unlock();}
private:
A *parent;
};
};
答案 1 :(得分:2)
这让我想起了Dr. Dobb's article by Andrei Alexandrescu。
这个想法是使用这样一个事实:就像const成员函数不能调用非const成员函数一样,volatile成员不能调用非易失性成员。然后他使用volatile来“标记”线程安全函数,而非易失性函数则“不安全”。所以这无法编译:
class Foo
{
public:
// Not the "volatile"
int External() volatile
{
return this->Internal();
}
private:
// Not volatile
int Internal();
};
因为this
无法从Foo volatile*
转换为Foo*
。演员是必要的。这是通过一个辅助类来实现的,它也扮演着RAII锁定持有者的角色。所以Foo变成了:
class Foo
{
public:
int External() volatile
{
Lock self(this);
return self->Internal();
}
private:
class Lock{
public:
explicit Lock(volatile Foo* Self)
: m_Mutex.Aquire(),
m_Self(const_cast<Foo*>(Self))
{}
~Lock()
{
m_Mutex.Release();
}
Foo* operator->(){
return m_Self;
}
private:
SomeMutexType m_Mutex;
Foo* m_Self;
};
int Internal();
};
答案 2 :(得分:0)
您可以使用'#Define'创建类似的效果:
#define CheckIfLocked(func, criticalSection) \
// here you can enter the critical section
func \
// exit critical section
答案 3 :(得分:0)
您可以使用C ++之一locking mechanisms。
使用其中一个“Try”-ing函数作为每个私有函数的第一步 - 这些函数只检查锁是否被锁定。如果未锁定,则抛出异常。
P.S。确保私有函数仅在 compile -time中从锁定状态调用...可能会很有趣...这可能在Haskell中可能:)
答案 4 :(得分:0)
在每个公共函数的开头锁定对象A一次,并在处理完成后释放锁定。公共职能是处理开始的入口点。您不必担心锁定每个私有函数。
查看RAII以锁定/解锁对象(或使用类似boost::mutex::scoped_lock的内容)。
答案 5 :(得分:0)
lock()函数锁定互斥锁并将线程id放入成员变量中。 unlock()将成员变量设置为0并解锁互斥锁
在你的私人函数中检查线程id是你自己的线程的,并且如果不是那么大声抱怨。