有一个lock
,可以为每个人提供对部分或资源的独占访问权限。并且ReaderWriterLock(Slim)
提供了对所有读者的共享访问权限以及对每位作者的独占访问权。
我正在寻找的是一种同步方法,允许对A组的共享访问和对B组的共享访问,但不允许同时对任何A和B进行共享访问。就读者/作者锁而言,这将是任意数量的读者,或任意数量的作者,但同时没有读者和作者。
解释它的另一种方法可能是有红绿灯的道路交叉点。只有一面有绿色。这边的每个人都可以通过交界处。一旦有人在另一侧排队,绿色就会变红。没人能进入交界处了。只有在每个人离开交叉路口后,下一个等待的一方才会变绿,而那边的每个人都可以通过。
.NET Framework中是否有适合的解决方案?或者我将使用哪些部分来实现这一目标?
信号量限制单个资源上的用户数,但不提供多个资源的协调。我现在还不知道其他任何可用的课程。
我正在使用PubSub系统(发布/订阅),可以在订阅时提供已发布的消息。订阅和取消订阅操作可以并行运行,它们正在更新内部注册数据,订阅操作也从消息缓冲区中读取,以确定要发送给新订户的过去消息。发布操作仅读取注册数据,但将新项添加到消息缓冲区并将其发送给订阅者。 (un)sub或pub操作可以并行运行,但不能同时运行。这对于防止发布的消息被发送两次(在sub和pub期间)以及防止消息丢失(在sub和pub之间)是必要的。
我尝试过解决但无法找到解决方案。这是我目前的草案代码:
using System;
using System.Threading;
public class MultiStateLock
{
// The current confirmed state
private int currentState;
// The state somebody is waiting to enter
private int awaitedState;
// The number of callers in the current state
private int enteredCount;
// Enters a state. Blocks until the state is switched.
public void Wait(int state)
{
// Is the current state not what we want to enter?
Thread.MemoryBarrier();
if (currentState != state)
{
var spinWait = new SpinWait();
// Is some other state currently being awaited? If not, await the new state
while (Interlocked.CompareExchange(ref awaitedState, state, 0) != 0 && awaitedState != state)
{
spinWait.SpinOnce();
}
// Is somebody else still entered in another state?
// TODO: These two variables need some synchronisation, without blocking Leave()
Thread.MemoryBarrier();
while (currentState != state && enteredCount > 0)
{
spinWait.SpinOnce();
Thread.MemoryBarrier();
}
// Switch the current state
currentState = state;
// Let others await another state
awaitedState = 0;
}
// Say we're in the state
// TODO: This may only be done if currentState wasn't already changed again
Interlocked.Increment(ref enteredCount);
}
// Leaves the entered state.
public void Leave()
{
Thread.MemoryBarrier();
if (enteredCount <= 0)
throw new InvalidOperationException("Cannot leave the state that wasn't entered.");
// NOTE: Maybe the state to be left could be verified, too.
// Or maybe this check could be removed altogether if it's not reliable.
// They shouldn't be needed in correct implementations.
// Say we're out of the state. Were we the last in this state?
if (Interlocked.Decrement(ref enteredCount) == 0)
{
// Let others switch to their awaited state
// TODO: This may only be done if enteredCount wasn't already incremented again
// (and effectively currentState hasn't changed)
currentState = 0;
}
}
}
它应该让尽可能多的呼叫者进入相同的状态。一旦任何呼叫者想要进入不同的状态,所有新呼叫者将不得不等待。当所有呼叫者都离开他们的状态时(所以没有人在短暂的时间内处于任何状态),第一个等待者可以进入他们的状态,所有等待相同状态的人都可以跟进。
我甚至不敢尝试。我知道它中缺少同步,只是通过思考。请参阅TODO和NOTE注释。我可以在lock
和Enter
周围放置Leave
,但由于Enter
将等待,它会在等待{{1}时阻止对Leave
的任何调用}} 跑步。这将是一个僵局。
我故意不使用Leave
字段作为may be improperly synchronised,我不会完全明白这一点。