两组操作之间的同步

时间:2018-05-05 22:11:49

标签: c# .net multithreading synchronization

有一个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注释。我可以在lockEnter周围放置Leave,但由于Enter将等待,它会在等待{{1}时阻止对Leave的任何调用}} 跑步。这将是一个僵局。

我故意不使用Leave字段作为may be improperly synchronised,我不会完全明白这一点。

0 个答案:

没有答案