在SignalR中使服务器端客户列表线程安全吗?

时间:2015-11-10 06:49:22

标签: c# thread-safety signalr

我正在尝试使我的服务器端线程安全。

目前,我正在使用List<ServerClient> m_connectedClients并在连接或断开连接时填写我的客户端,如下所示:

    public LoginStatus Connect(string connectionId, LoginRequestMessage message)
    {
        var status = m_databaseManager.CheckLogin(message.Username, message.Password);
        if (status == LoginStatus.Success)
        {
            var connection = m_connectedClients.FirstOrDefault(p => p.Username == message.Username);
            if (connection == null)
            {
                var client = m_databaseManager.GetClient(message.Username, connectionId);
                m_connectedClients.Add(client);
            }
            else if (!connection.ConnectionIds.Contains(connectionId))
            {
                connection.ConnectionIds.Add(connectionId);
            }
        }
        return status;
    }

    public void Disconnect(string connectionId)
    {
        foreach (var connection in m_connectedClients.Where(p => p.ConnectionIds.Contains(connectionId)))
        {
            connection.ConnectionIds.Remove(connectionId);
        }
        Console.WriteLine("Client disconnected... {0}", connectionId);
    }

在我的情况下,在某些情况下,我想做这样的事情:

    public bool IsLoggedIn(string connectionId)
    {
        if (m_connectedClients.Any(p => p.ConnectionIds.Contains(connectionId)))
        {
            return true;
        }
        return false;
    }

因此,简单地使用ConcurrentDictionary添加和删除内容可能不起作用(我甚至不知道,我会使用什么密钥,因为每个客户端可以有多个ConnectionId,这是我在这里唯一的标识符。

我能做的就是每次访问它时锁定List<ServerClient>,但是那里会有很多有锁的地方,所以我想这是一个糟糕的主意,对吗?

另一个问题是: 我到处都必须保持线程安全吗?或者仅在连接(添加)和断开连接(删除)时才重要,但在实际使用该列表时却不重要?

1 个答案:

答案 0 :(得分:1)

  

因此,简单地使用ConcurrentDictionary添加和删除内容可能不起作用(我甚至不知道,我会使用什么密钥,因为每个客户端可以有多个ConnectionId,这是我在这里唯一的标识符。

你是对的。 ConcurrentDictionary可能对您的用例太有限了。

  

我能做的就是每次访问时都锁定List,但是那里会有很多锁,所以我想这是一个糟糕的主意,对吗?

无法绕过它:每次访问列表时都应该锁定。创建一个类,它提供了需要列表的功能,并锁定并获取锁定,以便获取锁定不会分散在代码周围,也可能会被意外遗忘。

  

另一个问题是:我到处都必须保持线程安全吗?或者仅在连接(添加)和断开连接(删除)时才重要,但在实际使用该列表时却不重要?

线程安全是一个全局属性。如果你到处都没有线程安全,那么你就不是线程安全期。如果您有许多读取器和读取操作,并且只有很少的编写器和写入操作,那么请考虑使用针对此类方案优化的ReaderWriterLockSlim类。每次访问列表时都必须使用它。