【问题标题】:Thread.Join() doesn't wait until thread terminatesThread.Join() 不会等到线程终止
【发布时间】:2014-05-18 06:01:21
【问题描述】:

我正在创建一个服务器,当客户端连接时,我创建了一个线程,它监听来自客户端的消息,所以基本上只是 StreamReader.Readline()
创建此answerListener 线程的线程必须等到answerListener 线程终止,但它不会等待。

这是我的代码的一部分

            Thread answersListener = new Thread(new ThreadStart(StartListeningAnswers));
            answersListener.Name = Thread.CurrentThread.Name + "_listener";
            answersListener.Start();

            while (player.status.Equals(PlayerStatus.Playing))
            {
                CheckOpponentStatus();
                Thread.Yield();
            }

            DetermineResult(player.status);


            answersListener.Join();

            RuntimeInfo.Instance.playerList.TryDequeue(out player);

            player.Input.Close();
            player.Input.Dispose();
            player.Output.Close();
            player.Output.Dispose();
            player.Socket.Close();

            Console.WriteLine("client " + player.playerID + " disconnected");
            player = null;

这就是StartListeningAnswers() 方法的作用:

            while (player.status.Equals(PlayerStatus.Playing))
            {
                answer = player.Input.ReadLine();
                if (answer == null) return;
            }

这是StartListeningAnswers() 方法中的catch 块:

        catch (IOException e)
        {
            Console.WriteLine(player.playerID + " Connected = " + player.Socket.Connected);

            Console.WriteLine("ERROR: ReceiveAnswer from " + player.playerID);
            return;              
        }

当我运行我的服务器时,我在尝试在 StartListeningAnswers() 中执行 ReadLine() 时遇到异常

我在控制台输出中有以下顺序:
client 1 disconnected
1 Connected = False
ERROR: ReceiveAnswer from 1

所以我猜主线程不会等到玩家发送一些东西,而是继续执行并关闭流。

我做错了什么?

【问题讨论】:

    标签: c# multithreading inputstream streamreader


    【解决方案1】:

    您的代码存在一些问题。第一个是,你没有电话Thread.Yield()player.status 不是线程安全的 (http://rbwhitaker.wikidot.com/c-sharp-threading)。

    但主要问题是player.status 永远不会变成PlayerStatus.Playing,因此服务器中的while 循环永远不会中断。

    我不完全了解上下文并且 我会建议一种不同的方式来实现这一点,但你可以这样做:

    public void StartListeningAnswers()
    {
        try
        {
    
            while (player.status.Equals(PlayerStatus.Playing))
            {
                string answer = player.Input.ReadLine();
                if (string.IsNullOrEmpty( answer )) 
                    return;
            }
    
        }
        finally
        {
            player.status = PlayerStatus.Stopped;
        }
    }
    

    【讨论】:

    • 我应该在哪里使用Thread.Yield() 方法?我以为enum是线程安全的(msdn.microsoft.com/en-us/library/vstudio/…)有两种方法可以更改player.status:第一种是StartListeningAnswers()第二种方法是CheckOpponentStatus我只是删除了这部分代码,因为我认为它没有任何内容解决问题
    • 无处可去。 Windows 将处理线程片/时间。如果你喜欢线程上的等待,你可以看看ManualResetEvents。他们将以更少的 CPU 消耗来处理等待。
    • 枚举不是问题,枚举是常量(数字),但playerstatus变量是。
    • 谢谢,我会看看ManualResetEvent 并让player.status 线程安全。感谢您的帮助,如果有帮助,我会将您的解决方案标记为答案。
    • 我按照你的建议做了,但没有解决问题。你能推荐点别的吗?
    猜你喜欢
    • 2015-02-12
    • 1970-01-01
    • 1970-01-01
    • 2020-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多