如何同步线程实现多人猜词游戏轮流猜测?
猜词游戏线程同步问题
作业需求
我有一项学校作业,要编写一个猜词游戏:玩家通过Putty连接服务器,启动游戏后猜词,猜对即获胜,最多支持3人参与。要求使用多线程并实现线程同步,让玩家轮流猜测——一名玩家输入猜测内容时,其余玩家处于等待状态,之后依次轮到第二名、第三名玩家猜测。
我的疑问
- a) 该如何实现这种线程同步?我已尝试使用
Join,但不确定是否能达成需求; - b) 这种轮流等待的玩法是否适合作为线程应用的示例?
现有代码
Server类代码
/// <summary> /// 用于创建玩家服务器的构造函数。 /// </summary> /// <param name="port"> /// 连接服务器的端口 /// </param> public Server(int port) { myServer = new TcpListener(IPAddress.Any, port); myServer.Start(); isRunning = true; LoopServer(); }
/// <summary> /// 每次有新用户连接服务器时,创建一个新线程。 /// </summary> private void LoopServer() { while (isRunning) { TcpClient client = myServer.AcceptTcpClient(); Thread thread = new Thread(new ParameterizedThreadStart(LoopClient)); thread.Start(client); thread.Join(); } }
/// <summary> /// 游戏运行的方法 /// </summary> /// <param name="obj"></param> private void LoopClient(object obj) { try { TcpClient client = (TcpClient)obj; StreamReader reader = new StreamReader(client.GetStream(), Encoding.UTF8); StreamWriter writer = new StreamWriter(client.GetStream(), Encoding.UTF8); users.Add(new User(Thread.CurrentThread.ManagedThreadId)); writer.Flush(); puzzle.guessWord(writer, reader, users); Console.WriteLine("Out of the server"); } catch (Exception ex) { Console.WriteLine(ex.Message); } }
Game类代码
/// <summary> /// 每次玩家进行猜测时,将字符串添加到用户的猜测列表中 /// </summary> /// <param name="user"></param> /// <param name="userGuess"></param> /// <returns> /// 返回用户的猜测内容(字符串)以及进行猜测的玩家ID /// </returns> public string TakeGuess(User user, string userGuess) { user.Guesses.Add(Validation(userGuess)); return "Your guess:" + userGuess + " " + "player with id:" + user.Id; }
/// <summary> /// 游戏实际运行的方法 /// </summary> /// <param name="writer"></param> /// <param name="reader"></param> /// <param name="users"></param> public void guessWord(StreamWriter writer, StreamReader reader, List<User> users) { Console.Write("Connected"); bool gameIsPlaying = true; // 创建新用户,玩家ID表示其使用的线程 User user = new User(Thread.CurrentThread.ManagedThreadId); writer.WriteLine("Guessing game"); Console.WriteLine("Number of players in game:" + " " + users.Count); if (users.Count > 0) { while (gameIsPlaying) { string data = reader.ReadLine(); // writer输出的内容会显示在客户端(Putty)上 writer.WriteLine(TakeGuess(user, data)); if (Validation(data).Equals(this.Word)) { gameIsPlaying = false; Console.WriteLine("Winner is user with id" + " " + user.Id); writer.WriteLine("Winner is user with id" + " " + user.Id); users.Clear(); } } writer.WriteLine("The game is over"); } }
我已尝试按上述需求同步线程,但尚未实现预期效果。
解答
问题a:实现轮流猜测的线程同步方式
你当前用Thread.Join()的方式是错误的——在LoopServer里每次创建线程后立刻调用Join,会导致服务器只能串行处理玩家连接,第二个玩家必须等第一个玩家的游戏结束才能连上,完全达不到多玩家同时在线轮流猜测的效果。
要实现轮流猜测,你需要用显式的线程同步原语,比如Monitor(配合lock)来控制玩家的回合顺序,核心思路是用共享状态标记当前回合玩家,让非当前回合的线程等待,完成回合后切换并唤醒下一个线程:
在Game类中维护共享状态:
private readonly object _turnLock = new object(); private List<User> _allPlayers = new List<User>(); private int _currentPlayerIndex = 0; private bool _gameEnded = false;修改
guessWord方法,实现回合控制逻辑:public void guessWord(StreamWriter writer, StreamReader reader, User currentUser) { writer.WriteLine("猜词游戏 - 等待你的回合..."); writer.Flush(); int playerIndex = -1; // 玩家加入游戏,获取自身索引 lock (_turnLock) { if (_allPlayers.Count >= 3) { writer.WriteLine("游戏已满,无法加入"); writer.Flush(); return; } _allPlayers.Add(currentUser); playerIndex = _allPlayers.Count - 1; writer.WriteLine($"你是玩家{playerIndex + 1}"); writer.Flush(); } while (!_gameEnded) { lock (_turnLock) { // 等待直到轮到自己或游戏结束 while (_currentPlayerIndex != playerIndex && !_gameEnded) { Monitor.Wait(_turnLock); // 释放锁并等待通知 } if (_gameEnded) break; // 通知当前玩家可以猜测 writer.WriteLine("轮到你了,请输入猜测的单词:"); writer.Flush(); } // 读取玩家输入(不能放在锁内,避免阻塞其他线程) string userInput = reader.ReadLine(); string validatedGuess = Validation(userInput); lock (_turnLock) { writer.WriteLine(TakeGuess(currentUser, userInput)); writer.Flush(); // 判断是否猜对 if (validatedGuess.Equals(this.Word)) { _gameEnded = true; Console.WriteLine($"获胜者是玩家ID:{currentUser.Id}"); writer.WriteLine($"恭喜你猜对了!你是获胜者!"); writer.Flush(); // 唤醒所有等待的线程,告知游戏结束 Monitor.PulseAll(_turnLock); break; } // 切换到下一个玩家 _currentPlayerIndex = (_currentPlayerIndex + 1) % _allPlayers.Count; // 唤醒下一个玩家线程 Monitor.Pulse(_turnLock); } } writer.WriteLine("游戏结束"); writer.Flush(); }修正
LoopServer方法,移除thread.Join()让线程并行运行:private void LoopServer() { while (isRunning) { TcpClient client = myServer.AcceptTcpClient(); Thread thread = new Thread(new ParameterizedThreadStart(LoopClient)); thread.Start(client); // 移除thread.Join(),允许同时处理多个玩家连接 } }
问题b:轮流等待玩法是否适合作为线程应用示例
非常适合。这个场景完美对应了多线程环境下有序访问共享资源的核心需求:每个玩家的回合是一个需要按顺序执行的临界区,线程同步原语正好用来控制这种有序性。
它能直观展示:
- 多线程环境下共享状态的管理与竞态条件避免
- 线程等待、唤醒的协作机制
- 多用户交互场景下的线程同步逻辑
内容的提问来源于stack exchange,提问作者Petr
相关产品推荐
相关产品推荐

