0

わかりました。助けが必要です。信頼性を必要とするパケットが送信されると、ReliabilityLayerに渡されます。そこから、ReliabilityLayerはそのパケットをリストに追加し、SocketLayerに1回書き込みます。次に、ReliabilityLayerは、2つのタイマーを持つスレッドを生成します。パケットがまだリストにある間、最初のタイマーは250msごとにパケットをSocketLayerに継続的に送信します。2番目のタイマーはタイムアウト時間です。2秒後に例外をスローします。信頼性レイヤーはパケット受信イベントにフックし、信頼性レイヤーパケットリスト内のパケットのチェックサムを含むACKパケットが戻ってきたら、それを削除してスレッドを終了できるようにする必要があります。問題はマルチスレッドです...スレッド間でリストにアクセスすると、ランダムなnullポインターやその他の問題が発生します。だから私はそれをどうにかしてスレッドセーフにするか、この全体を再考する必要があります。誰かが私を助けることができるかどうか疑問に思いましたか?ありがとう

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);
            }
        }
4

1 に答える 1

3

この問題を解決する最も簡単な方法は、lock()を使用してListへの呼び出しを「保護」することです。あなたはそれをする方法をここでチェックすることができます。
簡単に説明すると、次のようになります。
次のようにスレッドセーフな操作を「保護」する必要はありません。

private object private_obj_to_be_used = new object();

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

挿入または削除だけでなく、読み取りも「保護」する必要があることに注意してください。または、「並行」クラスが自分に適しているかどうかを確認できます。

于 2012-11-29T20:39:25.923 に答える