7

我正在构建一个由服务器和客户端组成的小型聊天程序。服务器保留与之交互的客户端列表。

我在服务器上有两个工作线程。一个处理传入的客户端连接。另一个处理传入的客户端消息。

现在,由于两个线程都与一个名为“clients”的列表交互,所以我做了这样的事情。

// 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
            */
        }
    }
}

这是正确使用锁来防止我的列表同时被两个不同的线程更改吗?

到目前为止,我没有遇到任何问题,但我只是想确保它是正确的。

4

5 回答 5

8

这是正确的,但要确保 ClientHandler 不会持有锁太久。它不应该在阻塞时持有锁(例如,由套接字上的 IO 操作引起)。如果您违反此规则,您会发现您的吞吐量被破坏(仍然保持正确性)。

于 2012-04-15T20:38:04.057 回答
1

你有一个作家和多个读者吗?看看ReaderWriterLock这个集合

于 2012-04-15T20:41:52.047 回答
1

看起来还可以。聊天服务器对于多线程挑战来说非常棘手。锁内可能会引发异常,例如,当服务器-客户端套接字对象断开连接,但在其线程可以从列表中删除对象之前,另一个线程锁定列表并尝试写入断开连接的套接字。

于 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 回答