0

サーバークライアントプロジェクトを作成しています。ここで、サーバーはクライアントの呼び出しに基づいてデータベースに変更を加えます。クライアントの呼び出しは非同期です。イベントを使用して着信呼び出しに基づいていくつかのデリゲートを呼び出しています。以下のコードはあなたにアイデアを与えることができます

public delegate void Client_Logging_In_Delegate(WebSocketSession session, string e);
public event Client_Logging_In_Delegate Admin_Logging_In_Event;
public void Client_Logging_In_Function(WebSocketSession session, string e)
{
    //Database -> this particular client status= true
}

public void Main()
{
    server.NewMessageReceived += new SessionEventHandler<WebSocketSession, string>     (server.WebSocketServer_NewMessageReceived);

    server.Client_Logging_In_Event = new Client_Logging_In_Delegate(server.Client_Logging_In_Function);
}

public void WebSocketServer_NewMessageReceived(WebSocketSession session, string e)
{
    string type = e.Substring(0, e.IndexOf("#"));
    if (type == "Client_Logging_In")
        Client_Logging_In_Event(session, e);
}

両方を同じシステムで実行しています。私はまだクラッシュを受けていません。しかし、実際にはクライアント => 5 -> 20 です。問題は、2 つのイベントが同時に到着した場合、何が起こるかということです。

編集:

サーバー部分にサードパーティのライブラリ「SuperWebsocket」を使用しています。これは message_Received イベントを定義します。ドキュメントには、スレッドセーフであると書かれています。私のはシングルスレッドアプリケーションです。サーバー オブジェクトは 1 つだけです。一部の関数 (デリゲートによって呼び出される) には、いくつかの長いコードがあります。たとえば、これを取ります

public void called_By_Some_Delegate(WebSocketSession session, string e)
{
       //1) retrieve a big list from database
       //2) change the list into a dictionary object
       //3) create a string using dictionary object
       //4) send this string to the client using the "session" object
}

ここで、同じデリゲート/関数に対して 2 つのイベントが到着したとします。ここで、最初のポイントで関数が実行され、2 番目のポイントで実行されるとします。2 番目が同時に関数にアクセスすると、リストが変更されます。だから、私はクラッシュがあると思います。これは私が理解しなければならない状況です。

4

2 に答える 2

1

同時に言うと、サーバーにはリクエストをリッスンしてイベントを発生させるスレッドが複数あることを理解しています。この場合、各スレッドはイベントを発生させ、イベント ハンドラーはそれぞれのスレッドで問題なく実行されます (イベント ハンドラーがスレッド セーフである場合)。

そうでなく、ソケットをリッスンしているスレッドが 1 つしかない場合は、いずれにせよシーケンシャルであり、問​​題は発生しないはずです。

リッスンしているスレッドが着信要求を処理する別のスレッドをトリガーする場合、イベント ハンドラーを独自のスレッド コンテキストで実行し、ハンドラーがスレッド セーフである限り、安全です。

複数のリクエストを生成し、同じものを処理するサーバーをシミュレートするために、以下のプログラムを作成しました。

using System;
using System.Threading;
namespace AsyncFiber
{
    class Program
    {
        public event EventHandler<int> ClientEventReceived;
        public event EventHandler<int> MessageProcessed;
        static void Main(string[] args)
        {
            Program p = new Program();
            p.ClientEventReceived += p.p_ClientEventReceived;
            p.MessageProcessed += p.p_MessageProcessed;
            for (int i = 0; i < 5; i++)
                new Thread(new ThreadStart(p.target)).Start();
        }
        private void p_MessageProcessed(object sender, int e)
        {
            PrintHelper("C->" + e);
        }

        private void p_ClientEventReceived(object sender, int e)
        {
            MessageProcessed(sender, e);
        }

        void target()
        {
            while (true)
            {
                var data = new Random().Next();
                Console.WriteLine("P->" + data);
                ClientEventReceived(Thread.CurrentThread.Name, data);
            }
        }

        void PrintHelper(string message)
        {
            for (int i = 0; i < Thread.CurrentThread.ManagedThreadId; i++)
                Console.Write("  ");
            Console.Write(message);
            Console.WriteLine();
        }
    }
}

あなたの質問に答えるために、イベントハンドラーはそれぞれのスレッドで同時に実行されます。ただし、データベースのロック スキームは、このシナリオを処理するのに十分明確である必要があります。

于 2012-05-18T15:56:48.553 に答える
0

それは、イベントをどの程度正確にserver呼び出すかによって異なりNewMessageReceivedます。ただし、最も可能性の高いケースは、これにスレッド プール スレッドを使用し、複数の呼び出しに対して保護していないことです。これが意味することは、Client_Logging_In_Functionが同時に 2 回 (またはそれ以上) 実行される可能性があるということです。

デリゲートの呼び出し (イベントから来たかどうかに関係なく) は、通常のメソッドの呼び出しと非常に似ています。ロックやキューイングはなく、現在のスレッドで直接呼び出されます (を使用しない限りBeginInvoke())。

デリゲートの呼び出しとメソッドの直接呼び出しの唯一の違いは、デリゲートの呼び出しが間接的であること (デリゲートを呼び出すときにどのメソッドを呼び出すかを選択する必要はありません。以前に選択しました) であり、複数のメソッドを同時に呼び出すことができることです。この方法 (デリゲートが複数の単純なデリゲートの組み合わせである場合)。

于 2012-05-18T15:04:27.677 に答える