【问题标题】:Packet reliability multithread bugs数据包可靠性多线程错误
【发布时间】:2012-11-18 00:11:32
【问题描述】:

好的,我需要一些帮助。当一个需要可靠性的数据包被发送出去时,它会被传递到 ReliabilityLayer。 ReliabilityLayer 从那里将该数据包添加到列表中,然后将其一次写入 SocketLayer。 ReliabilityLayer 然后产生一个有 2 个定时器的线程。当数据包仍在列表中时,第一个计时器每 250 毫秒连续将数据包发送到 SocketLayer。第二个定时器是超时时间。它在 2 秒后抛出异常。 ReliabilityLayer 挂钩到数据包接收事件,当返回的 ACK 数据包包含 ReliabilityLayer 数据包列表中数据包的校验和时,它应该将其删除以允许线程退出。问题是多线程...跨线程访问列表会给我随机空指针和其他问题。所以我要么以某种方式使其线程安全,要么重新考虑整个事情。我想知道是否有人可以帮助我?谢谢

public void Write(NetworkPacket packet, ClientInfo client, Action<byte[], EndPoint> action)
        {
            if (CSL)
                throw new Exception("ReliabilityLayer loaded for client use.");

            if (!packet.Command.RequiresReliability())
                throw new ArgumentException("Packet does not require reliability.");

            //Add the packet to the reliability list
            packetList.Add(packet);

            //Send the packet to the socket layer.
            action.Invoke(packet.RawData, client.EndPoint);

            new Thread(() =>
            {
                Stopwatch timeout = new Stopwatch();
                Stopwatch timer = new Stopwatch();
                timer.Start();
                timeout.Start();
                while (packetList.Contains(packet))
                {
                    //Still no response from the remote connection -> send another packet
                    if (timer.ElapsedMilliseconds > 256)
                    {
                        action.Invoke(packet.RawData, client.EndPoint);
                        timer.Restart();
                    }

                    //No response after 2 seconds -> throw exception
                    if (timeout.ElapsedMilliseconds > 2048)
                    {
                        throw new Exception("Client has not responded to the request.");
                    }
                }
            }).Start();
        }

        private void ssl_OnPacketReceived(object sender, ServerPacketEventArgs e)
        {
            if (e.Packet.Command != Command.Ack)
                return;

            //Find matching packet in the packetList
            NetworkPacket packet = packetList.Find(pkt => pkt.Checksum == e.Packet.Data[0]); //e.Packet.Data[0] is the checksum of the packet that was send out.
            if (packet != null)
            {
                //Remove it to allow thread to exit
                packetList.Remove(packet);
            }
        }

【问题讨论】:

    标签: c# multithreading sockets udp reliability


    【解决方案1】:

    解决问题的最简单方法是使用 lock() 来“保护”任何对 List 的调用。 您可以查看here 操作方法。
    简而言之,解释如下:
    您应该按照以下方式“保护”非线程安全操作

    private object private_obj_to_be_used = new object();
    
    lock(private_obj_to_be_used)
    {
       /// not thread safe operation goes here<br/>
    }
    

    请注意,您不仅要“保护”插入或删除,还要“保护”读取。 或者您可以检查是否有适合您的“并发”课程。

    【讨论】:

    • 似乎是合法的,也许添加一个关于死锁的警告。
    • 该链接已损坏。此外,您最好发布完整的答案,这样如果链接另一端的页面出现故障,它仍然有用。
    • 谢谢,我查看了并发类,发现 .NET 有适合我的 SynchronizedCollection 类。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-23
    • 2012-11-02
    • 1970-01-01
    • 1970-01-01
    • 2018-05-24
    相关资源
    最近更新 更多