C# - 在单独的线程上错误地打印矩阵

时间:2014-01-27 15:49:16

标签: multithreading

我目前正在制作一款控制台应用程序游戏,我正在开发多人游戏版本。

当我收到数据包时,我会创建一个新线程来处理数据包,以便尽快返回ReceiveFrom命令。

新创建的帖子应该重新打印整个Matrix,使用它获得的关于矩阵变化的新信息(它应该打印具有更新的玩家位置的矩阵)。

问题是,当在新线程上调用Print方法时,执行得很糟糕。它非常不准确地打印矩阵,并且控制台屏幕上的矩阵的许多字符都很乱。

以下是方法:

    void Receive()
    {
        while (true)
        {
            byte[] msg = new byte[1024];
            client.Receive(msg);
            Thread handle = new Thread(() => HandleInput(msg));
            handle.Start();
        }
    }
    void HandleInput(byte[] msgX)
    {
        string data = Encoding.ASCII.GetString(msgX);
        data = data.Replace("\0", "");
        if (data.Contains('*') || data.Contains('\0') || data.Contains(' ')) // Move Packet (moving objects in a matrice)
        {
            // for example, a move packet can be: '*'!12!10
            char ToMove = char.Parse(data.Split('!')[0]);
            int X = int.Parse(data.Split('!')[1]);
            int Y = int.Parse(data.Split('!')[2]);
            grid[X, Y] = ToMove;
            Print();
        }
    }
    void Print() // print a 20x50 matrix
    {
        Console.Clear();
        for (int y = 0; y < 52; y++)
        {
            Console.Write('-');
        }
        Console.WriteLine();
        for (int i = 0; i < 20; i++)
        {
            Console.Write('|');
            for (int j = 0; j < 50; j++)
            {
                Console.Write(grid[i,j]);
            }
            Console.WriteLine('|');
        }
        for (int x = 0; x < 52; x++)
        {
            Console.Write('-');
        }
    }

但是,当我尝试处理输入并在Receive方法的同一个线程上打印矩阵时,它工作正常。打印它的问题只出现在我在单独的线程上打印矩阵时。

那么为什么会这样呢?为什么单独的线程不能正确打印矩阵?

1 个答案:

答案 0 :(得分:0)

您为每个接收到的千字节创建一个新线程,但不保证这些线程按顺序开始运行,彼此等待,也不能按顺序完成运行。

也无法保证网络客户端在Receive方法的一次调用中将收到所有必需的字节。它可能发生在一个,但它可能发生在几个电话中。也可能会发生连接另一端的两个Send方法合并为一条消息。在网络通信中保证的只是流中字节的排序,而不是其他任何内容。

您的下一个问题可能是“我该如何让它发挥作用”?我无法为你做这份工作,但一般来说我会这样做:

  1. 从流中读取大块字节并将其存储在某个缓冲区中。
  2. 检查循环中是否存在缓冲区中的完整消息。如果有这样的消息,则从缓冲区中删除该消息,并处理该消息。我会在同一个线程中处理它,并且只有在遇到这种方法的问题时我才会考虑其他线程(或者更确切地说是我将向其发送所有消息的另一个线程)。
  3. 重复循环,直到从缓冲区中删除所有完整的消息,然后继续读取流。