Frage

Ok I need some help. When a packet is sent out that requires reliability it gets passed to the ReliabilityLayer. From there the ReliabilityLayer adds that packet to a list then writes it once to the SocketLayer. The ReliabilityLayer then spawns a thread that has 2 timers. While the packet is still in the list the first timer continuously sends the packet to the SocketLayer every 250ms. The second timer is the timeout time. It throws an exception after 2s. The ReliabilityLayer hooks into the packet receive event and when an ACK packet comes back containing the checksum of a packet in the ReliabilityLayer packet list, it should remove it allowing the thread to exit. Problem is multithreading...Accessing the list across threads is giving me random null pointers and other problems. So I have to either make it thread safe somehow or rethink this whole thing. I was wondering if anyone could help me out? Thanks

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);
            }
        }
War es hilfreich?

Lösung

The easiest way to resolve the problem is to "guard" any calls to List with lock(). You can check here how to do it.
In short explanation is the following:
You should "guard" not thread safe operations following way

private object private_obj_to_be_used = new object();

lock(private_obj_to_be_used)
{
   /// not thread safe operation goes here<br/>
}

Please note that you have to "guard" not only inserts or removes but the reads also. Or you can check if there any "Concurrent" class is suitable for you.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top