use ReaderWriterLockSlim for lock Room.clients

This commit is contained in:
Robert Paciorek 2024-04-03 15:53:24 +00:00 committed by Spirtix
parent d0c1839b11
commit a4039451f3
2 changed files with 27 additions and 10 deletions

View File

@ -85,7 +85,8 @@ public class GauntletRoom : Room {
} }
public bool ProcessResult(Client client, string resultA, string resultB) { public bool ProcessResult(Client client, string resultA, string resultB) {
lock (base.roomLock) { base.roomLock.EnterWriteLock();
try {
players[client].resultA = resultA; players[client].resultA = resultA;
players[client].resultB = resultB; players[client].resultB = resultB;
@ -112,6 +113,8 @@ public class GauntletRoom : Room {
Send(packet); Send(packet);
return true; return true;
} finally {
base.roomLock.ExitWriteLock();
} }
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Threading;
using sodoffmmo.Data; using sodoffmmo.Data;
namespace sodoffmmo.Core; namespace sodoffmmo.Core;
@ -8,7 +9,7 @@ public class Room {
protected static Dictionary<string, Room> rooms = new(); protected static Dictionary<string, Room> rooms = new();
List<Client> clients = new(); List<Client> clients = new();
protected object roomLock = new object(); protected ReaderWriterLockSlim roomLock = new ReaderWriterLockSlim();
public int Id { get; private set; } public int Id { get; private set; }
public string Name { get; private set; } public string Name { get; private set; }
@ -38,40 +39,53 @@ public class Room {
public IEnumerable<Client> Clients { public IEnumerable<Client> Clients {
get { get {
List<Client> list; List<Client> list;
lock (roomLock) { roomLock.EnterReadLock();
list = new List<Client>(clients); try {
return new List<Client>(clients);
} finally {
roomLock.ExitReadLock();
} }
return list;
} }
} }
public void AddClient(Client client) { public void AddClient(Client client) {
lock (roomLock) { roomLock.EnterWriteLock();
try {
if (IsRemoved) if (IsRemoved)
throw new Exception("Call AddClient on removed room"); throw new Exception("Call AddClient on removed room");
client.Send(RespondJoinRoom()); client.Send(RespondJoinRoom());
// NOTE: send RespondJoinRoom() and add client to clients as atomic operation // NOTE: send RespondJoinRoom() and add client to clients as atomic operation
// to make sure to client get full list of players in room // to make sure to client get full list of players in room
clients.Add(client); clients.Add(client);
} finally {
roomLock.ExitWriteLock();
} }
} }
public void RemoveClient(Client client) { public void RemoveClient(Client client) {
lock (roomLock) { roomLock.EnterWriteLock();
try {
clients.Remove(client); clients.Remove(client);
if (AutoRemove && ClientsCount == 0) { if (AutoRemove && ClientsCount == 0) {
IsRemoved = true; IsRemoved = true;
rooms.Remove(Name); rooms.Remove(Name);
} }
} finally {
roomLock.ExitWriteLock();
} }
} }
public void Send(NetworkPacket packet, Client? skip = null) { public void Send(NetworkPacket packet, Client? skip = null) {
roomLock.EnterReadLock();
try {
foreach (var roomClient in clients) { foreach (var roomClient in clients) {
if (roomClient != skip) { if (roomClient != skip) {
roomClient.Send(packet); roomClient.Send(packet);
} }
} }
} finally {
roomLock.ExitReadLock();
}
} }
public static bool Exists(string name) => rooms.ContainsKey(name); public static bool Exists(string name) => rooms.ContainsKey(name);