【发布时间】:2020-12-10 20:54:47
【问题描述】:
CreateNewRound() 方法在运行时被多个线程访问。假设 _game.CurrentRound = 99 并且两个线程同时访问该方法,它们都将 currentRoundId 初始化为 100,并且两个线程都添加了两个具有相同 roundId 的实体。但这是错误的,我不希望这种情况发生,因为回合应该是独特的和不同的。我该如何解决这个问题,以便线程一个添加一个第 100 轮的实体,另一个添加第 101 轮的实体。
public void CreateNewRound()
{
var game = _cache.GetGameById(_session.gameId);
var currentRoundId = game.CurrentRound + 1;
var response = SomeAPI.SomeCall();
if (response.responseCode == (int)responseCodes.Success)
{
_dbContext.GameState.Add(new GameState() { RoundId = CurrentRoundId });
_dbContext.SaveChanges();
}
}
【问题讨论】:
-
@Artavazd 是的,但您只有一个资源,在这种情况下,您必须使用监视器(或二进制信号量);无论如何,当其他线程已经在使用相同的资源时,您必须阻止其他线程执行某些操作,因此您不在乎这是否较慢,正确运行很重要。附言C# 中的监视器是作为锁实现的。
-
如果多个线程可以在同一轮中调用这个,你显然不能使用轮号作为唯一ID。您必须引入另一个(或额外的)ID 来消除歧义。
-
@Artavazd “不应用锁会使我的代码变慢吗?” - 很有可能。但这有问题吗? - 我建议实施解决问题的最简单的解决方案(即最少的更改)并对其进行基准测试。如果您不喜欢基准测试的结果:找到下一个更复杂的解决方案,将焦点从“最少的更改”转移到“速度”。然后再次测量...
-
是的。锁会使您的代码变慢。 完全与交通信号灯使汽车行驶速度变慢的方式相同 - 因此它们不会相互碰撞。基本上这是你的选择——要么接受你的代码运行错误的事实,要么接受你的代码等待其他代码完成的事实。你不能两者兼得。 (或者找到一个不依赖线程访问相同资源的解决方案,从而消除同步的需要)
标签: c# .net multithreading thread-safety