我并不是直接询问有关互斥锁的内容,尽管有些相关。
有两组函数A和B.当A中的函数运行时,B中的任何函数都不应该运行,反之亦然。
有多个线程可以调用A或B中的函数,并且应满足上述要求。
我可以通过混合一些锁定方式来想办法来做到这一点,但我很担心最好的方法是什么,或者至少是一些缩小范围的好方法。
答案 0 :(得分:4)
好的,所以有三种有效状态:
没有任何线程在任何一组中运行函数。
一个或多个线程正在A组中运行功能。
一个或多个线程在B组中运行。
与大多数复杂的锁定方案一样,这可以通过锁内的状态来管理。状态可以是枚举,例如(EgsFree,EgsAonly,EgsBonly),threadCount int,用于跟踪受保护函数中任一组的线程数以及同步对象的容器(不允许运行的线程)等待。
函数需要通过在进入时调用锁定状态(用参数标识其组)和退出来进行协作。
在尝试输入时发现它们不允许运行其功能的线程必须通过引发事件/信号量,将其存储在容器中并在退出锁定状态后等待它来阻止自己。这允许线程将计数递减为0(并因此将状态再次设置为Efree),在退出时迭代容器并使所有等待的线程都准备就绪。
鉴于此框架,您可以根据需要实施反饥饿算法或其他管理方案。
锁中的状态数据很混乱,我希望看到一个更简单的解决方案。 OTOH,它仍然是复杂资源管理的唯一安全方式,我知道这可以依赖于工作并且没有隐藏的种族/死锁潜力。如果你必须对锁定方案过于考虑,那么它可能会在某些时候搞砸了:)
答案 1 :(得分:3)
在我看到Martin James的回答之前,我正在编写这段代码。事实证明,这是未经测试的c ++ 11代码,可以说明他的答案,所以请大声回答。
我认为带引用计数的三向开关可能有效(未经测试的类)
struct ThreeWaySwitch
{
std::mutex mtx;
std::condition_variable cv;
enum State { IDLE, A, B } state;
int count;
ThreeWaySwitch() : state(IDLE), count(0) {}
void switchA()
{
std::unique_lock l(mtx);
while (state == B) cv.wait(l);
state = A;
++count;
}
void switchB()
{
std::unique_lock l(mtx);
while (state == A) cv.wait(l);
state = B;
++count;
}
void switchIdle()
{
{
std::unique_lock(mtx);
if (count == 0) return; // already idle
if (--count != 0) return; // not idle yet
state = IDLE;
}
cv.notify_all();
}
};
因此每个A函数在entry上调用switchA(),在exit上调用switchIdle(),为B函数调用switchB()。
答案 2 :(得分:0)
我试图找到问题的更开放/简单的答案,你可以这样做:
class A
{
public:
static void foo1();
static void foo2();
private:
static std::shared_ptr<MyMutexClass> m_mmc;
};
class B
{
public:
static void foo3();
static void foo4();
private:
static std::shared_ptr<MyMutexClass> m_mmc;
};
在你的foo功能中,使用组提供的静态互斥锁来保护。 您只需要找到一种方法来正确初始化A :: m_mmc和B :: m_mmc。