c#2队列之间的同步

时间:2015-07-15 02:12:32

标签: c# concurrency queue server barrier

我正在尝试计算如何将并发访问同步到2个相关队列

我有一台服务器,处理来自多个客户端的请求。 那些客户想要一起玩(一对一),他们会指定他们是否想先开始。 我必须通过排队所有客户来处理他们的游戏请求,然后通过配对来匹配它们(想要首先对抗那些不想先玩的人),让他们知道是否找到了匹配的队友

到目前为止我尝试了什么:

internal class ClientsManager
{
    #region Members

    /// <summary>
    /// The player list.
    /// </summary>
    private static readonly ConcurrentDictionary<string, DateTime> m_players = new ConcurrentDictionary<string, DateTime>();
    private static readonly ConcurrentDictionary<string, TcpClientManager> m_managers = new ConcurrentDictionary<string, TcpClientManager>();
    private static readonly ConcurrentDictionary<string, string> m_duos = new ConcurrentDictionary<string, string>();

    /// <summary>
    /// The player waiting for a teammate.
    /// </summary>
    private static readonly BlockingCollection<string> m_waitingTeammate = new BlockingCollection<string>(1);
    private static readonly ConcurrentDictionary<string, DateTime> m_waitingTeammates = new ConcurrentDictionary<string, DateTime>();

    /// <summary>
    /// Random number generator.
    /// </summary>
    private static readonly Random m_Random = new Random();

    /// <summary>
    /// The related <see cref="T:ArcheageServer.TcpClientManager" />.
    /// </summary>
    private readonly TcpClientManager m_clientManager;

    #endregion

    #region Constructors

    static ClientsManager()
    {
        Task.Factory.StartNew(CheckPlayers, TaskCreationOptions.LongRunning);
    }

    internal ClientsManager(TcpClientManager clientManager)
    {
        Contract.Requires<ArgumentNullException>(clientManager != null);

        m_clientManager = clientManager;
    }

    #endregion

    #region Methods

    /// <summary>
    /// Define the invariant valid state for this class.
    /// </summary>
    [ContractInvariantMethod]
    private void InvariantValidState()
    {
        Contract.Invariant(m_clientManager != null);
    }

    private static void CheckPlayers()
    {
        while (true)
        {
            var list = m_players.Where(kvp => (DateTime.Now - kvp.Value).TotalMilliseconds > Settings.Default.ClientTimeout).ToList();
            if (list.Count > 0)
                list.ForEach(kvp => RemovePlayer(kvp.Key));
            Thread.Sleep(Settings.Default.ServerIdleTime);
        }
    }

    internal void Handle(Packet packet)
    {
        Contract.Requires<ArgumentNullException>(packet != null);
        throw new NotImplementedException(String.Format("The packet Type {0} handle has not been implemented yet.", packet.GetType().ToString()));
    }

    internal void Handle(C0KeepAlivePacket c0KeepALivePacket)
    {
        Contract.Requires<ArgumentNullException>(c0KeepALivePacket != null);
        UpdatePlayer(c0KeepALivePacket.PlayerName, DateTime.Now);
    }

    internal void Handle(C1WantToPlayPacket c1WantToPlayPacket)
    {
        Contract.Requires<ArgumentNullException>(c1WantToPlayPacket != null);
        Contract.Assert(m_clientManager != null);

        var playerName = c1WantToPlayPacket.PlayerName;
        var waitTimeout = c1WantToPlayPacket.WaitTimeout;
        var startWaiting = DateTime.Now;
        bool shouldWait;

        UpdatePlayer(playerName, startWaiting);
        if (m_waitingTeammates.ContainsKey(playerName))
        {
            m_clientManager.Server.SendPacket(m_clientManager, new S2PlayAuthorizationPacket(true));
            return;
        }

        string teammate = null;
        while ((shouldWait = ShouldWait(playerName, startWaiting, waitTimeout)) && !FindOrWaitForTeammate(playerName, out teammate)) Thread.Sleep(10);
        if (shouldWait)
        {
            if (teammate == null)
            {
                m_waitingTeammates.AddOrUpdate(playerName, startWaiting, (name, moment) => startWaiting);

                while ((shouldWait = ShouldWait(playerName, startWaiting, waitTimeout)) && m_waitingTeammates.ContainsKey(playerName)) Thread.Sleep(10);
                if (!shouldWait)
                {
                    m_waitingTeammate.TryTake(out teammate);
                    m_waitingTeammates.TryRemove(playerName, out startWaiting);
                }
            }
            else
            {
                m_waitingTeammates.TryRemove(teammate, out startWaiting);
                m_duos.TryAdd(playerName, teammate);
                m_duos.TryAdd(teammate, playerName);
            }
        }
        m_clientManager.Server.SendPacket(m_clientManager, new S2PlayAuthorizationPacket(shouldWait));
    }

    private void UpdatePlayer(string playerName, DateTime startWaiting)
    {
        m_players.AddOrUpdate(playerName, startWaiting, (name, moment) => startWaiting);
        m_managers.AddOrUpdate(playerName, m_clientManager, (name, manager) => m_clientManager);
    }

    private static void RemovePlayer(string playerName)
    {
        string teammate;
        DateTime startWaiting;
        m_waitingTeammates.TryRemove(playerName, out startWaiting);
        m_players.TryRemove(playerName, out startWaiting);
        m_duos.TryRemove(playerName, out teammate);
        TcpClientManager tcpClientManager;
        if (m_managers.TryRemove(teammate, out tcpClientManager))
            tcpClientManager.Server.SendPacket(tcpClientManager, new S6StopPlayPacket());
        m_managers.TryRemove(playerName, out tcpClientManager);
        m_duos.TryRemove(teammate, out playerName);
    }

    private bool FindOrWaitForTeammate(string playerName, out string teammate)
    {
        teammate = null;
        return m_waitingTeammate.TryAdd(playerName) || m_waitingTeammate.TryTake(out teammate);
    }

    private static bool ShouldWait(string playerName, DateTime startWaiting, int waitTimeout)
    {
        return m_players.ContainsKey(playerName) && (DateTime.Now - startWaiting).TotalMilliseconds < waitTimeout;
    }

    #endregion
}

我尝试使用障碍类而没有取得更多成功:

    private static Barrier m_waitFirsts = new Barrier(1, (b) =>
    {
        while (m_goFirsts)
        {
            Console.WriteLine("wait winners");
            m_wait.SignalAndWait();
            Console.WriteLine("winners waited");
        }
        Console.WriteLine("winners false");
        m_goFirsts = false;
    });
    private static Barrier m_waitLoosers = new Barrier(1, (b) =>
    {
        while (m_goSeconds)
        {
            Console.WriteLine("wait loosers");
            m_wait.SignalAndWait();
            Console.WriteLine("loosers waited");
        }
        Console.WriteLine("m_goLoosers false");
        m_goSeconds = false;
    });
    private static Barrier m_wait = new Barrier(2, (b) =>
    {
        Console.WriteLine("m_go false");
        m_go = false;
    });

    private static bool m_goFirsts = true;
    private static bool m_goSeconds = true;
    private static bool m_go = true;

    internal void Handle(C1WantToPlayPacket c1WantToPlayPacket)
    {
        Console.WriteLine(c1WantToPlayPacket.ToString());
        while (m_go)
        {
            Console.WriteLine(c1WantToPlayPacket.PlayerName);
            if ((c1WantToPlayPacket.IsWinner ? m_waitFirsts : m_waitLoosers).SignalAndWait(c1WantToPlayPacket.WaitTimeout))
                Console.WriteLine(c1WantToPlayPacket.PlayerName + " YES");
            else
                Console.WriteLine(c1WantToPlayPacket.PlayerName + " NO");
        }
    }

很容易阻挡,直到找到2名玩家,然后继续,但无法处理1名第一名和1名玩家的特定情况......

我是否错过了使用任何框架类的简单方法? 我的代码看起来很丑陋,我必须维护很多并发集合来实现一个简单的任务

0 个答案:

没有答案