Browse Source

fix!: 🐛 fix deadlock problem of spectator

tags/0.1.0
TCL 3 years ago
parent
commit
9dbe08c67d
4 changed files with 53 additions and 26 deletions
  1. +2
    -2
      logic/Client/Properties/launchSettings.json
  2. +15
    -9
      logic/Server/GameServer.cs
  3. +2
    -2
      logic/Server/Properties/launchSettings.json
  4. +34
    -13
      logic/Server/RpcServices.cs

+ 2
- 2
logic/Client/Properties/launchSettings.json View File

@@ -2,7 +2,7 @@
"profiles": {
"Client": {
"commandName": "Project",
"commandLineArgs": "--port 8888 --characterID 3 --type 1 --occupation 5"
"commandLineArgs": "--port 8892 --characterID 8880 --type 1 --occupation 1 --ip thuai6.eesast.com --cl"
}
}
}
}

+ 15
- 9
logic/Server/GameServer.cs View File

@@ -11,14 +11,15 @@ using Playback;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Preparation.Interface;
using System.Collections.Concurrent;


namespace Server
{
public partial class GameServer : AvailableService.AvailableServiceBase
{
private Dictionary<long, (SemaphoreSlim, SemaphoreSlim)> semaDict = new();
private object semaDictLock = new();
private ConcurrentDictionary<long, (SemaphoreSlim, SemaphoreSlim)> semaDict = new();
// private object semaDictLock = new();
protected readonly ArgumentOptions options;
private HttpSender? httpSender;
private object gameLock = new();
@@ -29,13 +30,13 @@ namespace Server
private SemaphoreSlim endGameSem = new(0);
protected readonly Game game;
private uint spectatorMinPlayerID = 2023;
private List<uint> spectatorList = new List<uint>();
public int playerNum;
public int TeamCount => options.TeamCount;
protected long[] communicationToGameID; // 通信用的ID映射到游戏内的ID,通信中0-3为Student,4为Tricker
private readonly object messageToAllClientsLock = new();
public static readonly long SendMessageToClientIntervalInMilliseconds = 50;
private MessageWriter? mwr = null;
private object spetatorJoinLock = new();

public void StartGame()
{
@@ -169,14 +170,19 @@ namespace Server
break;
}
}
foreach (var kvp in semaDict)
lock (spetatorJoinLock)
{
kvp.Value.Item1.Release();
}
foreach (var kvp in semaDict)
{
kvp.Value.Item1.Release();
}

foreach (var kvp in semaDict)
{
kvp.Value.Item2.Wait();
// 若此时观战者加入,则死锁,所以需要 spetatorJoinLock

foreach (var kvp in semaDict)
{
kvp.Value.Item2.Wait();
}
}
}
private bool playerDeceased(int playerID)


+ 2
- 2
logic/Server/Properties/launchSettings.json View File

@@ -2,7 +2,7 @@
"profiles": {
"Server": {
"commandName": "Project",
"commandLineArgs": "--ip 0.0.0.0 -p 8888 --characterID 2030"
"commandLineArgs": "--port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --fileName video"
}
}
}
}

+ 34
- 13
logic/Server/RpcServices.cs View File

@@ -16,6 +16,7 @@ namespace Server
{
public partial class GameServer : AvailableService.AvailableServiceBase
{
private int playerCountNow = 0;
protected object spectatorLock = new object();
protected bool isSpectatorJoin = false;
protected bool IsSpectatorJoin
@@ -59,17 +60,18 @@ namespace Server
if (request.PlayerId >= spectatorMinPlayerID && options.NotAllowSpectator == false)
{
// 观战模式
uint tp = (uint)request.PlayerId;
if (!spectatorList.Contains(tp))
lock (spetatorJoinLock) // 具体原因见另一个上锁的地方
{
spectatorList.Add(tp);
Console.WriteLine("A new spectator comes to watch this game.");
var temp = (new SemaphoreSlim(0, 1), new SemaphoreSlim(0, 1));
lock (semaDictLock)
if (semaDict.TryAdd(request.PlayerId, (new SemaphoreSlim(0, 1), new SemaphoreSlim(0, 1))))
{
semaDict.Add(request.PlayerId, temp);
Console.WriteLine("A new spectator comes to watch this game.");
IsSpectatorJoin = true;
}
else
{
Console.WriteLine($"Duplicated Spectator ID {request.PlayerId}");
return;
}
IsSpectatorJoin = true;
}
do
{
@@ -82,13 +84,30 @@ namespace Server
//Console.WriteLine("Send!");
}
}
catch (InvalidOperationException)
{
if (semaDict.TryRemove(request.PlayerId, out var semas))
{
try
{
semas.Item1.Release();
semas.Item2.Release();
}
catch { }
Console.WriteLine($"The spectator {request.PlayerId} exited");
}
}
catch (Exception)
{
//Console.WriteLine(ex);
// Console.WriteLine(ex);
}
finally
{
semaDict[request.PlayerId].Item2.Release();
try
{
semaDict[request.PlayerId].Item2.Release();
}
catch { }
}
} while (game.GameMap.Timer.IsGaming);
return;
@@ -117,10 +136,12 @@ namespace Server
var temp = (new SemaphoreSlim(0, 1), new SemaphoreSlim(0, 1));
bool start = false;
Console.WriteLine($"Id: {request.PlayerId} joins.");
lock (semaDictLock)
// lock (semaDictLock)
{
semaDict.Add(request.PlayerId, temp);
start = (semaDict.Count - spectatorList.Count) == playerNum;
if (semaDict.TryAdd(request.PlayerId, temp))
{
start = Interlocked.Increment(ref playerCountNow) == playerNum;
}
}
if (start) StartGame();
}


Loading…
Cancel
Save