How to implement a performant thread-safe collection of elements that are not blocking each other when...
For an implementation of a games browser I need a collection of games that can be read and written by different threads. I want the elements of the collection to be as independent of each other as possible. I feel like changing one game should not disturb another game. Thats why I am hesitating to make use of the ReaderWriterLockSlim class when changing a game. As of now I am using a combination of a simple lock object within the game class and the ReaderWriterLockSlim class as follows:
- Consumer: Multiple threads. One for every client that requests the collection of games. They are using EnterReadLock.
- Producer (add): One thread for adding new games to the collection if required. After it finishes its work it will be called through a timer later again. It is using EnterUpgradeableReadLock once and EnterWriteLock for every required new game.
- Producer (modify): Multiple threads. Up to at least one for every game that exists in the collection. Every thread is always solely going to change one game. There may be multiple threads for one game. To access the right game in the collection they are making use of EnterReadLock. To prevent multiple threads from interfering when processing the same game, I am using an additional simple lock object on the game class right now.
As of this article Are IEnumerable Linq methods thread-safe? I know, that modifying the collection invalidates the enumerator and its behavior becomes undefined. But I am not sure, how to solve it properly.
So my Problem is: Modifying producers may change the elements of the collection while either
- adding producers may add new elements or
- consumers may iterate over the collection via linq expressions.
What do you suggest? Does a thread that wants to change a game really have to EnterWriteLock, thus preventing other games from being updated at the same time? Am I too concerned about performance issues?
Sample code:
public class Game
{
private readonly IList<Player> players;
public Game(int id, string name, GameMode mode)
{
ID = id;
Name = name;
Mode = mode;
Status = GameStatus.WaitingForPlayers;
players = new List<Player>();
}
public object Lock { get; private set; } = new object();
public int ID { get; }
public string Name { get; }
public GameMode Mode { get; }
public GameStatus Status { get; private set; }
public int PlayerCount => players.Count;
public void Join(Player player)
{
// Just an example...
players.Add(player);
}
public void Leave(Player player)
{
players.Remove(player);
}
public void Start()
{
// Just an example...
Status = GameStatus.Started;
}
public GameDto ToDto() => new GameDto(ID, Name, Mode, Status, PlayerCount);
// Just an example. Depends on if it was started already and so on...
public bool CanStart => PlayerCount > 3;
}
public class Server : IDisposable
{
private readonly ReaderWriterLockSlim gamesLock = new ReaderWriterLockSlim();
// This is the collection, that is giving me headaches.
private ICollection<Game> games = new List<Game>();
// ... Constructor and more ...
// Will be called once in a while but not in parallel. Adds games, if available games are full...
private void AddRequiredGames()
{
while (TryGetRequiredGame(GetGames(), out Game game))
{
gamesLock.EnterWriteLock();
games.Add(game);
gamesLock.ExitWriteLock();
}
}
// Will be called once the last player left a game. There may be multiple threads at once for different games.
private void RemoveIfObsolete(Game game)
{
gamesLock.EnterUpgradeableReadLock();
lock (game.Lock)
{
#warning Here I am eventually iterating over the collection, while its elements could be modified.
if (game.IsEmpty && games.Count(item => item.Mode == game.Mode
&& item.Status == GameStatus.WaitingForPlayers) > 3)
{
// ToDo - Mark game as obsolete to prevent incoming join attempts.
gamesLock.EnterWriteLock();
games.Remove(game);
gamesLock.ExitWriteLock();
}
}
gamesLock.ExitUpgradeableReadLock();
}
private ICollection<GameDto> GetGames()
{
gamesLock.EnterReadLock();
#warning Here I am iterating over the collection, while its elements could be modified.
IList<GameDto> result = games.Select(item => item.ToDto()).ToList();
gamesLock.ExitReadLock();
return result;
}
// Will be called asynchronously be every client that requests to join a game.
private void HandlePlayerJoin(Player player, Game game)
{
lock (game.Lock)
{
#warning Here I am modifying an element of the collection without locking the collection.
game.Join(player);
}
// Just an example. Wouldn't try to start the game, if the player could not join etc...
TryStartGame(game);
}
private void TryStartGame(Game game)
{
lock (game.Lock)
{
if (game.CanStart)
#warning Here I am modifying an element of the collection without locking the collection.
game.Start();
}
}
// Will be called asynchronously be every client that requests the list of games.
private void HandleGetGames(Client client)
{
client.Send(new GetGamesResponse(GetGames()));
}
}
c# multithreading
|
show 2 more comments
For an implementation of a games browser I need a collection of games that can be read and written by different threads. I want the elements of the collection to be as independent of each other as possible. I feel like changing one game should not disturb another game. Thats why I am hesitating to make use of the ReaderWriterLockSlim class when changing a game. As of now I am using a combination of a simple lock object within the game class and the ReaderWriterLockSlim class as follows:
- Consumer: Multiple threads. One for every client that requests the collection of games. They are using EnterReadLock.
- Producer (add): One thread for adding new games to the collection if required. After it finishes its work it will be called through a timer later again. It is using EnterUpgradeableReadLock once and EnterWriteLock for every required new game.
- Producer (modify): Multiple threads. Up to at least one for every game that exists in the collection. Every thread is always solely going to change one game. There may be multiple threads for one game. To access the right game in the collection they are making use of EnterReadLock. To prevent multiple threads from interfering when processing the same game, I am using an additional simple lock object on the game class right now.
As of this article Are IEnumerable Linq methods thread-safe? I know, that modifying the collection invalidates the enumerator and its behavior becomes undefined. But I am not sure, how to solve it properly.
So my Problem is: Modifying producers may change the elements of the collection while either
- adding producers may add new elements or
- consumers may iterate over the collection via linq expressions.
What do you suggest? Does a thread that wants to change a game really have to EnterWriteLock, thus preventing other games from being updated at the same time? Am I too concerned about performance issues?
Sample code:
public class Game
{
private readonly IList<Player> players;
public Game(int id, string name, GameMode mode)
{
ID = id;
Name = name;
Mode = mode;
Status = GameStatus.WaitingForPlayers;
players = new List<Player>();
}
public object Lock { get; private set; } = new object();
public int ID { get; }
public string Name { get; }
public GameMode Mode { get; }
public GameStatus Status { get; private set; }
public int PlayerCount => players.Count;
public void Join(Player player)
{
// Just an example...
players.Add(player);
}
public void Leave(Player player)
{
players.Remove(player);
}
public void Start()
{
// Just an example...
Status = GameStatus.Started;
}
public GameDto ToDto() => new GameDto(ID, Name, Mode, Status, PlayerCount);
// Just an example. Depends on if it was started already and so on...
public bool CanStart => PlayerCount > 3;
}
public class Server : IDisposable
{
private readonly ReaderWriterLockSlim gamesLock = new ReaderWriterLockSlim();
// This is the collection, that is giving me headaches.
private ICollection<Game> games = new List<Game>();
// ... Constructor and more ...
// Will be called once in a while but not in parallel. Adds games, if available games are full...
private void AddRequiredGames()
{
while (TryGetRequiredGame(GetGames(), out Game game))
{
gamesLock.EnterWriteLock();
games.Add(game);
gamesLock.ExitWriteLock();
}
}
// Will be called once the last player left a game. There may be multiple threads at once for different games.
private void RemoveIfObsolete(Game game)
{
gamesLock.EnterUpgradeableReadLock();
lock (game.Lock)
{
#warning Here I am eventually iterating over the collection, while its elements could be modified.
if (game.IsEmpty && games.Count(item => item.Mode == game.Mode
&& item.Status == GameStatus.WaitingForPlayers) > 3)
{
// ToDo - Mark game as obsolete to prevent incoming join attempts.
gamesLock.EnterWriteLock();
games.Remove(game);
gamesLock.ExitWriteLock();
}
}
gamesLock.ExitUpgradeableReadLock();
}
private ICollection<GameDto> GetGames()
{
gamesLock.EnterReadLock();
#warning Here I am iterating over the collection, while its elements could be modified.
IList<GameDto> result = games.Select(item => item.ToDto()).ToList();
gamesLock.ExitReadLock();
return result;
}
// Will be called asynchronously be every client that requests to join a game.
private void HandlePlayerJoin(Player player, Game game)
{
lock (game.Lock)
{
#warning Here I am modifying an element of the collection without locking the collection.
game.Join(player);
}
// Just an example. Wouldn't try to start the game, if the player could not join etc...
TryStartGame(game);
}
private void TryStartGame(Game game)
{
lock (game.Lock)
{
if (game.CanStart)
#warning Here I am modifying an element of the collection without locking the collection.
game.Start();
}
}
// Will be called asynchronously be every client that requests the list of games.
private void HandleGetGames(Client client)
{
client.Send(new GetGamesResponse(GetGames()));
}
}
c# multithreading
You can just make yourGamethread-safe itself, and then all of them into aConcurrentDictionary. This way, you will safely extract add remove game from collections in a lock-free manner, and then you can safely do whatever you want with your game. You can useReaderWriteLockSlim, if it is mostly read-only operations, but use it insideGame, notServer.
– Yeldar Kurmangaliyev
Nov 25 '18 at 16:32
InHandlePlayerJoinandTryStartGameI see no reason you would need to lock around the collection, because you already have aGamereference. During this time thisGamecould be removed from the collection, but does that matter to you?
– Rotem
Nov 25 '18 at 16:32
InRemoveIfObsolete, you write "Here I am eventually iterating over the collection, while its elements could be modified.", but this is not true, because you are inside a read lock. No other thread can get a write lock while you are inside the read lock.
– Rotem
Nov 25 '18 at 16:34
@Rotem: Thanks for your input. Removing theGamereference even temporary from the collection withinHandlePlayerJoinorTryStartGamewould mean that players may not see it when invokingHandleGetGamesduring that time. Thats not really what I want. InRemoveIfObsoleteI am inside a read lock for the collection but as of nowHandlePlayerJoincould modify the collection anyways, because the method only acquires a lock for its own game whereasRemoveOfObsoletecould be dealing with a completely different game meanwhile.
– FLav0ured
Nov 25 '18 at 17:06
@Yeldar Kurmangaliyev: Thank your for your advice. MakingGamethread-safe sounds interesting indeed. I have to think/implement this through, I guess. Same goes for theConcurrentDictionary. I will try it out.
– FLav0ured
Nov 25 '18 at 17:19
|
show 2 more comments
For an implementation of a games browser I need a collection of games that can be read and written by different threads. I want the elements of the collection to be as independent of each other as possible. I feel like changing one game should not disturb another game. Thats why I am hesitating to make use of the ReaderWriterLockSlim class when changing a game. As of now I am using a combination of a simple lock object within the game class and the ReaderWriterLockSlim class as follows:
- Consumer: Multiple threads. One for every client that requests the collection of games. They are using EnterReadLock.
- Producer (add): One thread for adding new games to the collection if required. After it finishes its work it will be called through a timer later again. It is using EnterUpgradeableReadLock once and EnterWriteLock for every required new game.
- Producer (modify): Multiple threads. Up to at least one for every game that exists in the collection. Every thread is always solely going to change one game. There may be multiple threads for one game. To access the right game in the collection they are making use of EnterReadLock. To prevent multiple threads from interfering when processing the same game, I am using an additional simple lock object on the game class right now.
As of this article Are IEnumerable Linq methods thread-safe? I know, that modifying the collection invalidates the enumerator and its behavior becomes undefined. But I am not sure, how to solve it properly.
So my Problem is: Modifying producers may change the elements of the collection while either
- adding producers may add new elements or
- consumers may iterate over the collection via linq expressions.
What do you suggest? Does a thread that wants to change a game really have to EnterWriteLock, thus preventing other games from being updated at the same time? Am I too concerned about performance issues?
Sample code:
public class Game
{
private readonly IList<Player> players;
public Game(int id, string name, GameMode mode)
{
ID = id;
Name = name;
Mode = mode;
Status = GameStatus.WaitingForPlayers;
players = new List<Player>();
}
public object Lock { get; private set; } = new object();
public int ID { get; }
public string Name { get; }
public GameMode Mode { get; }
public GameStatus Status { get; private set; }
public int PlayerCount => players.Count;
public void Join(Player player)
{
// Just an example...
players.Add(player);
}
public void Leave(Player player)
{
players.Remove(player);
}
public void Start()
{
// Just an example...
Status = GameStatus.Started;
}
public GameDto ToDto() => new GameDto(ID, Name, Mode, Status, PlayerCount);
// Just an example. Depends on if it was started already and so on...
public bool CanStart => PlayerCount > 3;
}
public class Server : IDisposable
{
private readonly ReaderWriterLockSlim gamesLock = new ReaderWriterLockSlim();
// This is the collection, that is giving me headaches.
private ICollection<Game> games = new List<Game>();
// ... Constructor and more ...
// Will be called once in a while but not in parallel. Adds games, if available games are full...
private void AddRequiredGames()
{
while (TryGetRequiredGame(GetGames(), out Game game))
{
gamesLock.EnterWriteLock();
games.Add(game);
gamesLock.ExitWriteLock();
}
}
// Will be called once the last player left a game. There may be multiple threads at once for different games.
private void RemoveIfObsolete(Game game)
{
gamesLock.EnterUpgradeableReadLock();
lock (game.Lock)
{
#warning Here I am eventually iterating over the collection, while its elements could be modified.
if (game.IsEmpty && games.Count(item => item.Mode == game.Mode
&& item.Status == GameStatus.WaitingForPlayers) > 3)
{
// ToDo - Mark game as obsolete to prevent incoming join attempts.
gamesLock.EnterWriteLock();
games.Remove(game);
gamesLock.ExitWriteLock();
}
}
gamesLock.ExitUpgradeableReadLock();
}
private ICollection<GameDto> GetGames()
{
gamesLock.EnterReadLock();
#warning Here I am iterating over the collection, while its elements could be modified.
IList<GameDto> result = games.Select(item => item.ToDto()).ToList();
gamesLock.ExitReadLock();
return result;
}
// Will be called asynchronously be every client that requests to join a game.
private void HandlePlayerJoin(Player player, Game game)
{
lock (game.Lock)
{
#warning Here I am modifying an element of the collection without locking the collection.
game.Join(player);
}
// Just an example. Wouldn't try to start the game, if the player could not join etc...
TryStartGame(game);
}
private void TryStartGame(Game game)
{
lock (game.Lock)
{
if (game.CanStart)
#warning Here I am modifying an element of the collection without locking the collection.
game.Start();
}
}
// Will be called asynchronously be every client that requests the list of games.
private void HandleGetGames(Client client)
{
client.Send(new GetGamesResponse(GetGames()));
}
}
c# multithreading
For an implementation of a games browser I need a collection of games that can be read and written by different threads. I want the elements of the collection to be as independent of each other as possible. I feel like changing one game should not disturb another game. Thats why I am hesitating to make use of the ReaderWriterLockSlim class when changing a game. As of now I am using a combination of a simple lock object within the game class and the ReaderWriterLockSlim class as follows:
- Consumer: Multiple threads. One for every client that requests the collection of games. They are using EnterReadLock.
- Producer (add): One thread for adding new games to the collection if required. After it finishes its work it will be called through a timer later again. It is using EnterUpgradeableReadLock once and EnterWriteLock for every required new game.
- Producer (modify): Multiple threads. Up to at least one for every game that exists in the collection. Every thread is always solely going to change one game. There may be multiple threads for one game. To access the right game in the collection they are making use of EnterReadLock. To prevent multiple threads from interfering when processing the same game, I am using an additional simple lock object on the game class right now.
As of this article Are IEnumerable Linq methods thread-safe? I know, that modifying the collection invalidates the enumerator and its behavior becomes undefined. But I am not sure, how to solve it properly.
So my Problem is: Modifying producers may change the elements of the collection while either
- adding producers may add new elements or
- consumers may iterate over the collection via linq expressions.
What do you suggest? Does a thread that wants to change a game really have to EnterWriteLock, thus preventing other games from being updated at the same time? Am I too concerned about performance issues?
Sample code:
public class Game
{
private readonly IList<Player> players;
public Game(int id, string name, GameMode mode)
{
ID = id;
Name = name;
Mode = mode;
Status = GameStatus.WaitingForPlayers;
players = new List<Player>();
}
public object Lock { get; private set; } = new object();
public int ID { get; }
public string Name { get; }
public GameMode Mode { get; }
public GameStatus Status { get; private set; }
public int PlayerCount => players.Count;
public void Join(Player player)
{
// Just an example...
players.Add(player);
}
public void Leave(Player player)
{
players.Remove(player);
}
public void Start()
{
// Just an example...
Status = GameStatus.Started;
}
public GameDto ToDto() => new GameDto(ID, Name, Mode, Status, PlayerCount);
// Just an example. Depends on if it was started already and so on...
public bool CanStart => PlayerCount > 3;
}
public class Server : IDisposable
{
private readonly ReaderWriterLockSlim gamesLock = new ReaderWriterLockSlim();
// This is the collection, that is giving me headaches.
private ICollection<Game> games = new List<Game>();
// ... Constructor and more ...
// Will be called once in a while but not in parallel. Adds games, if available games are full...
private void AddRequiredGames()
{
while (TryGetRequiredGame(GetGames(), out Game game))
{
gamesLock.EnterWriteLock();
games.Add(game);
gamesLock.ExitWriteLock();
}
}
// Will be called once the last player left a game. There may be multiple threads at once for different games.
private void RemoveIfObsolete(Game game)
{
gamesLock.EnterUpgradeableReadLock();
lock (game.Lock)
{
#warning Here I am eventually iterating over the collection, while its elements could be modified.
if (game.IsEmpty && games.Count(item => item.Mode == game.Mode
&& item.Status == GameStatus.WaitingForPlayers) > 3)
{
// ToDo - Mark game as obsolete to prevent incoming join attempts.
gamesLock.EnterWriteLock();
games.Remove(game);
gamesLock.ExitWriteLock();
}
}
gamesLock.ExitUpgradeableReadLock();
}
private ICollection<GameDto> GetGames()
{
gamesLock.EnterReadLock();
#warning Here I am iterating over the collection, while its elements could be modified.
IList<GameDto> result = games.Select(item => item.ToDto()).ToList();
gamesLock.ExitReadLock();
return result;
}
// Will be called asynchronously be every client that requests to join a game.
private void HandlePlayerJoin(Player player, Game game)
{
lock (game.Lock)
{
#warning Here I am modifying an element of the collection without locking the collection.
game.Join(player);
}
// Just an example. Wouldn't try to start the game, if the player could not join etc...
TryStartGame(game);
}
private void TryStartGame(Game game)
{
lock (game.Lock)
{
if (game.CanStart)
#warning Here I am modifying an element of the collection without locking the collection.
game.Start();
}
}
// Will be called asynchronously be every client that requests the list of games.
private void HandleGetGames(Client client)
{
client.Send(new GetGamesResponse(GetGames()));
}
}
c# multithreading
c# multithreading
edited Nov 26 '18 at 17:37
FLav0ured
asked Nov 25 '18 at 16:14
FLav0uredFLav0ured
194
194
You can just make yourGamethread-safe itself, and then all of them into aConcurrentDictionary. This way, you will safely extract add remove game from collections in a lock-free manner, and then you can safely do whatever you want with your game. You can useReaderWriteLockSlim, if it is mostly read-only operations, but use it insideGame, notServer.
– Yeldar Kurmangaliyev
Nov 25 '18 at 16:32
InHandlePlayerJoinandTryStartGameI see no reason you would need to lock around the collection, because you already have aGamereference. During this time thisGamecould be removed from the collection, but does that matter to you?
– Rotem
Nov 25 '18 at 16:32
InRemoveIfObsolete, you write "Here I am eventually iterating over the collection, while its elements could be modified.", but this is not true, because you are inside a read lock. No other thread can get a write lock while you are inside the read lock.
– Rotem
Nov 25 '18 at 16:34
@Rotem: Thanks for your input. Removing theGamereference even temporary from the collection withinHandlePlayerJoinorTryStartGamewould mean that players may not see it when invokingHandleGetGamesduring that time. Thats not really what I want. InRemoveIfObsoleteI am inside a read lock for the collection but as of nowHandlePlayerJoincould modify the collection anyways, because the method only acquires a lock for its own game whereasRemoveOfObsoletecould be dealing with a completely different game meanwhile.
– FLav0ured
Nov 25 '18 at 17:06
@Yeldar Kurmangaliyev: Thank your for your advice. MakingGamethread-safe sounds interesting indeed. I have to think/implement this through, I guess. Same goes for theConcurrentDictionary. I will try it out.
– FLav0ured
Nov 25 '18 at 17:19
|
show 2 more comments
You can just make yourGamethread-safe itself, and then all of them into aConcurrentDictionary. This way, you will safely extract add remove game from collections in a lock-free manner, and then you can safely do whatever you want with your game. You can useReaderWriteLockSlim, if it is mostly read-only operations, but use it insideGame, notServer.
– Yeldar Kurmangaliyev
Nov 25 '18 at 16:32
InHandlePlayerJoinandTryStartGameI see no reason you would need to lock around the collection, because you already have aGamereference. During this time thisGamecould be removed from the collection, but does that matter to you?
– Rotem
Nov 25 '18 at 16:32
InRemoveIfObsolete, you write "Here I am eventually iterating over the collection, while its elements could be modified.", but this is not true, because you are inside a read lock. No other thread can get a write lock while you are inside the read lock.
– Rotem
Nov 25 '18 at 16:34
@Rotem: Thanks for your input. Removing theGamereference even temporary from the collection withinHandlePlayerJoinorTryStartGamewould mean that players may not see it when invokingHandleGetGamesduring that time. Thats not really what I want. InRemoveIfObsoleteI am inside a read lock for the collection but as of nowHandlePlayerJoincould modify the collection anyways, because the method only acquires a lock for its own game whereasRemoveOfObsoletecould be dealing with a completely different game meanwhile.
– FLav0ured
Nov 25 '18 at 17:06
@Yeldar Kurmangaliyev: Thank your for your advice. MakingGamethread-safe sounds interesting indeed. I have to think/implement this through, I guess. Same goes for theConcurrentDictionary. I will try it out.
– FLav0ured
Nov 25 '18 at 17:19
You can just make your
Game thread-safe itself, and then all of them into a ConcurrentDictionary. This way, you will safely extract add remove game from collections in a lock-free manner, and then you can safely do whatever you want with your game. You can use ReaderWriteLockSlim, if it is mostly read-only operations, but use it inside Game, not Server.– Yeldar Kurmangaliyev
Nov 25 '18 at 16:32
You can just make your
Game thread-safe itself, and then all of them into a ConcurrentDictionary. This way, you will safely extract add remove game from collections in a lock-free manner, and then you can safely do whatever you want with your game. You can use ReaderWriteLockSlim, if it is mostly read-only operations, but use it inside Game, not Server.– Yeldar Kurmangaliyev
Nov 25 '18 at 16:32
In
HandlePlayerJoin and TryStartGame I see no reason you would need to lock around the collection, because you already have a Game reference. During this time this Game could be removed from the collection, but does that matter to you?– Rotem
Nov 25 '18 at 16:32
In
HandlePlayerJoin and TryStartGame I see no reason you would need to lock around the collection, because you already have a Game reference. During this time this Game could be removed from the collection, but does that matter to you?– Rotem
Nov 25 '18 at 16:32
In
RemoveIfObsolete, you write "Here I am eventually iterating over the collection, while its elements could be modified.", but this is not true, because you are inside a read lock. No other thread can get a write lock while you are inside the read lock.– Rotem
Nov 25 '18 at 16:34
In
RemoveIfObsolete, you write "Here I am eventually iterating over the collection, while its elements could be modified.", but this is not true, because you are inside a read lock. No other thread can get a write lock while you are inside the read lock.– Rotem
Nov 25 '18 at 16:34
@Rotem: Thanks for your input. Removing the
Game reference even temporary from the collection within HandlePlayerJoin or TryStartGame would mean that players may not see it when invoking HandleGetGames during that time. Thats not really what I want. In RemoveIfObsolete I am inside a read lock for the collection but as of now HandlePlayerJoin could modify the collection anyways, because the method only acquires a lock for its own game whereas RemoveOfObsolete could be dealing with a completely different game meanwhile.– FLav0ured
Nov 25 '18 at 17:06
@Rotem: Thanks for your input. Removing the
Game reference even temporary from the collection within HandlePlayerJoin or TryStartGame would mean that players may not see it when invoking HandleGetGames during that time. Thats not really what I want. In RemoveIfObsolete I am inside a read lock for the collection but as of now HandlePlayerJoin could modify the collection anyways, because the method only acquires a lock for its own game whereas RemoveOfObsolete could be dealing with a completely different game meanwhile.– FLav0ured
Nov 25 '18 at 17:06
@Yeldar Kurmangaliyev: Thank your for your advice. Making
Game thread-safe sounds interesting indeed. I have to think/implement this through, I guess. Same goes for the ConcurrentDictionary. I will try it out.– FLav0ured
Nov 25 '18 at 17:19
@Yeldar Kurmangaliyev: Thank your for your advice. Making
Game thread-safe sounds interesting indeed. I have to think/implement this through, I guess. Same goes for the ConcurrentDictionary. I will try it out.– FLav0ured
Nov 25 '18 at 17:19
|
show 2 more comments
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53469389%2fhow-to-implement-a-performant-thread-safe-collection-of-elements-that-are-not-bl%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53469389%2fhow-to-implement-a-performant-thread-safe-collection-of-elements-that-are-not-bl%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
You can just make your
Gamethread-safe itself, and then all of them into aConcurrentDictionary. This way, you will safely extract add remove game from collections in a lock-free manner, and then you can safely do whatever you want with your game. You can useReaderWriteLockSlim, if it is mostly read-only operations, but use it insideGame, notServer.– Yeldar Kurmangaliyev
Nov 25 '18 at 16:32
In
HandlePlayerJoinandTryStartGameI see no reason you would need to lock around the collection, because you already have aGamereference. During this time thisGamecould be removed from the collection, but does that matter to you?– Rotem
Nov 25 '18 at 16:32
In
RemoveIfObsolete, you write "Here I am eventually iterating over the collection, while its elements could be modified.", but this is not true, because you are inside a read lock. No other thread can get a write lock while you are inside the read lock.– Rotem
Nov 25 '18 at 16:34
@Rotem: Thanks for your input. Removing the
Gamereference even temporary from the collection withinHandlePlayerJoinorTryStartGamewould mean that players may not see it when invokingHandleGetGamesduring that time. Thats not really what I want. InRemoveIfObsoleteI am inside a read lock for the collection but as of nowHandlePlayerJoincould modify the collection anyways, because the method only acquires a lock for its own game whereasRemoveOfObsoletecould be dealing with a completely different game meanwhile.– FLav0ured
Nov 25 '18 at 17:06
@Yeldar Kurmangaliyev: Thank your for your advice. Making
Gamethread-safe sounds interesting indeed. I have to think/implement this through, I guess. Same goes for theConcurrentDictionary. I will try it out.– FLav0ured
Nov 25 '18 at 17:19