You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何同步线程实现多人猜词游戏轮流猜测?

猜词游戏线程同步问题

作业需求

我有一项学校作业,要编写一个猜词游戏:玩家通过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)来控制玩家的回合顺序,核心思路是用共享状态标记当前回合玩家,让非当前回合的线程等待,完成回合后切换并唤醒下一个线程:

  1. 在Game类中维护共享状态:

    private readonly object _turnLock = new object();
    private List<User> _allPlayers = new List<User>();
    private int _currentPlayerIndex = 0;
    private bool _gameEnded = false;
    
  2. 修改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();
    }
    
  3. 修正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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 11:05:18