c# - 使我的代码线程安全时遇到问题
问题描述
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();
}
}
解决方案
如果(且仅当)所有调用的方法都是纯的,即结果仅取决于输入参数,您可以简单地使用 interlocked.Increment 来确保 currentRound 对于每个调用都是唯一的:
private int currentRound = 0;
public void CreateNewRound()
{
var thisRound = Interlocked.Increment(ref currentRound);
var gamestate = CreateGameState(thisRound)
// process game state
}
在大多数游戏中,下一轮将取决于上一轮的游戏状态。在这种情况下,您必须按顺序运行每一轮。典型的解决方案是为此使用锁:
private int currentRound = 0;
private object myLock = new object();
private MyGameState gameState;
public void CreateNewRound()
{
lock (myLock)
{
currentRound++;
gameState = ComputeNextGameState(gameState, currentRound);
// process game state
}
}
还有其他选择,例如分配一个特定线程来执行所有游戏状态更新,并且CreateNewRound
只要求更新线程进行更新。
推荐阅读
- huggingface-transformers - 如何从问答管道中获得分数?使用问答管道时是否存在错误?
- c++ - C++20:为什么ranges::subrange 对unique_ptr 失败?
- javascript - 无法修复未捕获的类型错误:e.target 未定义
- amazon-web-services - 在 Route 53 购买的域上的 DNS_PROBE_FINISHED_NXDOMAIN
- iis - 在浏览器中使用 https://dev:8080/ 或其他 CNAME 而不会出现安全错误
- assembly - 在 gdb 中执行指令/命令
- python-3.x - 如何使用 pytube 取消和暂停下载?
- qt - 如何在qml中使用中继器连续显示图像?
- c - 如何知道非阻塞recv返回0时会发生哪种情况?
- amazon-web-services - 与输入参数并行的 aws 阶跃函数