我正在尝试计算如何将并发访问同步到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名玩家的特定情况......
我是否错过了使用任何框架类的简单方法? 我的代码看起来很丑陋,我必须维护很多并发集合来实现一个简单的任务