7

サーバーとクライアントで構成される小さなチャット プログラムを作成しています。サーバーは、対話するクライアントのリストを保持しています。

サーバー上に 2 つのワーカー スレッドがあります。1 つは着信クライアント接続を処理します。もう 1 つは受信クライアント メッセージを処理します。

さて、両方のスレッドが「クライアント」と呼ばれるリストと対話するので、私はこのようなことをしました。

// The clients list looks something like this...
List<TcpClient> clients;

// This is running on one thread.
ConnectionHandler()
{
    while(true)
    {
        // Wait for client to connect, etc. etc.

        // Now, add the client to my clients List.
        lock(clients)clients.Add(myNewClient);
    }
}

// This is running on another thread.
ClientHandler()
{
    while(true)
    {
        lock(clients)
        {
            /*
            This will be handling things like incoming messages
            and clients disconnecting (clients being removed from
            the 'clients' List
            */
        }
    }
}

これは、リストが 2 つの異なるスレッドによって同時に変更されるのを防ぐためのロックの正しい使用法ですか?

これまでのところ問題はありませんでしたが、正しいことを確認したいだけです。

4

5 に答える 5

8

これは正しいですが、ClientHandler が長時間ロックを保持しないようにしてください。ブロック中にロックを保持してはなりません (たとえば、ソケットでの IO 操作が原因)。このルールに違反すると、スループットが破壊されていることがわかります (正確性は維持されています)。

于 2012-04-15T20:38:04.057 に答える
1

単一のライターと複数のリーダーがありますか? ReaderWriterLock とこのcollectionsを見てください。

于 2012-04-15T20:41:52.047 に答える
1

ちょっとOKに見えます。チャットサーバーは、マルチスレッドに挑戦する人にとって非常に扱いにくいものです。ロック内で例外が発生する可能性があります。たとえば、サーバー クライアント ソケット オブジェクトが切断されたが、そのスレッドがリストからオブジェクトを削除する前に、別のスレッドがリストをロックし、切断されたソケットに書き込もうとした場合です。

于 2012-04-15T20:48:15.073 に答える
0

注(上)-フィールドを初期化しないため(つまり、いつ破棄して再初期化するかなど、どのように行うかわかりません)-同じインスタンスをロックしていることを確認してください。コードの実行中に変更される可能性のあるオブジェクトのこのロックを参照してください

于 2012-04-15T20:40:50.610 に答える
0

私には問題ないように見えますが、この修正を行います。

private readonly List<TcpClient> clients = new List<TcpClient>();

コンストラクターでリストを作成することもできますが、それをreadonlyのままにしておきます。これは、同じオブジェクトをロックしていることを確認するための鍵です。そうしないと、clientsリストを再作成した場合、コードはスレッドセーフではなくなります。

于 2012-04-17T14:23:35.237 に答える