0

この例のような二重サービス ( NetTcpBinding)を作成しました。パブリッシュ/サブスクライブ パターンを使用し、新しいクライアントからの接続要求ごとに、サービスの新しいインスタンス (異なるコールバックを含む) を作成します。この例では、コールバックはイベントとデリゲートを通じて呼び出されます。

ここで、この例を変更したいと思います。クライアントの要求にすぐに応答したくない、つまり、一定の時間間隔の後にコールバック メソッドを呼び出したいとします。この場合、コールバックのメソッドへの参照を維持する必要があります...しかし、その間に一部のクライアントが切断された場合はどうなりますか? サービス インスタンスが破棄され、コールバックも失われます...

私はこの例を書きました:

  • MySingletonTableコールバックのメソッドへの参照を格納するデータ構造です。
  • SampleServiceサービスではありませんが、サービスのインスタンスをシミュレートします。

    public delegate void ProcessingHandler(string item, double price, double change);
    
    public class MySingletonTable
    {
        private static volatile MySingletonTable m_Instance;
        private static object syncRoot = new object();
    
        private static Dictionary<string, ProcessingHandler> pointersToHandlers;
    
        private MySingletonTable()
        {
            pointersToHandlers = new Dictionary<string, ProcessingHandler>();
        }
    
        // Return the singleton instance of this class.
        public static MySingletonTable Instance
        {
            get
            {
                if (m_Instance == null)
                {
                    lock (syncRoot)
                    {
                        if (m_Instance == null)
                            m_Instance = new MySingletonTable();
                    }
                }
                return m_Instance;
            }
        }
    
        /// The number of the entries in the table.
        public int Count
        {
            get
            {
                lock (syncRoot)
                {
                    return pointersToHandlers.Count;
                }
            }
        }
    
        // Add an handler.
        public void Add(string id, ProcessingHandler handler)
        {
            lock (syncRoot)
            {
                if (!pointersToHandlers.ContainsKey(id))
                    pointersToHandlers.Add(id, handler);
            }
        }
    
        // Get an handler from the table.
        public ProcessingHandler GetHandler(string id)
        {
            ProcessingHandler handler = null;
            lock (syncRoot)
            {
                if (pointersToHandlers.ContainsKey(id))
                    handler = pointersToHandlers[id];
            }
            return handler;
        }
    
        // Remove the specified handler.
        public bool Remove(string id)
        {
            lock (syncRoot)
            {
                return pointersToHandlers.Remove(id);
            }
        }
    }
    
    // This class simulates the service.
    public class SampleService
    {
        private static int counter = 0;
        private int service_i = ++counter;
    
        MySingletonTable reference = MySingletonTable.Instance;
    
        public SampleService(string id)
        {
            reference.Add(id, PriceChange);
        }
    
        private void PriceChange(string item, double price, double change)
        {
            // call the callback
            // ...
            Console.WriteLine("service_i {0}: {1} {2} {3}", service_i, item, price, change);
        }
    }
    
    
    class Program
    {
        static void Main(string[] args)
        {
            SampleService s1 = new SampleService("abc");
            SampleService s2 = new SampleService("def");
    
            MySingletonTable table = MySingletonTable.Instance;
            ProcessingHandler handler = null;
    
            handler = table.GetHandler("abc");
            handler("item one", 10, 20);
    
            handler = table.GetHandler("def");
            handler("item two", 30, 40);
    
            Console.ReadLine();
        }
    }
    

明らかに、この例でシミュレートされた 2 つのサービス インスタンスを明示的に破棄することはできません。しかし、サービスの 2 つのインスタンスが 2 つの異なるクライアントに関連しているs1としたらどうなるでしょうか?s2

4

3 に答える 3

1

デリゲートがpointersToHandlersに格納されている場合、これはオブジェクトを保持するため、ガベージコレクションが行われることはなく、「破棄」と呼ばれることもありません。事実上、現在メモリリークも発生しています。

クライアントが切断したとき(またはオブジェクトが破棄されると予想されるときはいつでも)、リストからデリゲートを削除する必要があります。イベントを使用していない理由はわかりませんが、それは別の質問です。イベントを使用する場合でも、この状況に陥らないように、終了したら切断する必要があります。

于 2012-06-25T21:08:23.210 に答える
1

さて、ローカル変数 S1 と S2 を null に設定しています。ただし、ディクショナリにはまだオブジェクトへのアドレスがあります。new オペレーターによって作成された SampleService は、s1 = null を実行しても削除されないため、ハンドラーの呼び出しは引き続き機能します。これは、次のことと同じです。

var s1 = new SampleService("aa");
var handler = s1;
s1 = null;

ハンドラーは、作成されたオブジェクトをまだ参照しています。

于 2012-06-25T22:08:17.493 に答える