C#多线程模拟大富翁游戏出现玩家位置异常及崩溃问题
问题原因分析
你的核心问题是多线程之间共享了同一个Player实例,导致并发修改可变状态时出现竞态条件,最终破坏了Player的Position数据。
具体代码问题
在PrepareGame方法中,你创建了一个全局的players列表,然后将这个列表直接传递给每一个新创建的Game对象。这意味着所有线程中的Game.Players指向的都是同一批Player实例。当多个线程同时调用p.Move()修改同一个Player的Position时,由于Position的更新操作不是原子性的,会出现以下典型的竞态场景:
- 线程A读取Player的当前Position值(比如5)
- 线程B同时读取同一个Player的Position值(还是5)
- 线程A计算新位置(5+3=8)并写入
- 线程B计算新位置(5+4=9)并写入
此时线程A的更新被覆盖,更严重的是如果涉及减法操作(比如入狱扣位置),交错的读写可能直接导致Position变为负数。
为什么Thread.Sleep()只能缓解不能解决
添加Thread.Sleep()只是降低了线程间操作重叠的概率,但并没有从根本上阻止并发访问。竞态条件是随机发生的,只要共享可变状态的问题存在,就总会有概率出现数据损坏。
修复方向
每个游戏模拟都应该拥有独立的Player实例,避免跨线程共享。修改创建Game的代码,为每个游戏克隆一份Player对象:
// 替换原Game构造调用,为每个游戏创建新的Player实例 var gamePlayers = players.Select(p => new Player(p.Name)).ToList(); GameLoop(new Game(i, board, gamePlayers));
这样每个线程的游戏都会操作自己的Player对象,线程间不会互相干扰。
另外,如果你的Board类也包含可变状态(比如地块的所有权、建筑等级等),同样需要为每个游戏创建独立的Board实例,避免跨游戏共享状态。
内容的提问来源于stack exchange,提问作者Titus Tesche
相关产品推荐
相关产品推荐

