我正在尝试使我的服务器端线程安全。
目前,我正在使用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>
,但是那里会有很多有锁的地方,所以我想这是一个糟糕的主意,对吗?
另一个问题是: 我到处都必须保持线程安全吗?或者仅在连接(添加)和断开连接(删除)时才重要,但在实际使用该列表时却不重要?
答案 0 :(得分:1)
因此,简单地使用ConcurrentDictionary添加和删除内容可能不起作用(我甚至不知道,我会使用什么密钥,因为每个客户端可以有多个ConnectionId,这是我在这里唯一的标识符。
你是对的。 ConcurrentDictionary可能对您的用例太有限了。
我能做的就是每次访问时都锁定List,但是那里会有很多锁,所以我想这是一个糟糕的主意,对吗?
无法绕过它:每次访问列表时都应该锁定。创建一个类,它提供了需要列表的功能,并锁定并获取锁定,以便获取锁定不会分散在代码周围,也可能会被意外遗忘。
另一个问题是:我到处都必须保持线程安全吗?或者仅在连接(添加)和断开连接(删除)时才重要,但在实际使用该列表时却不重要?
线程安全是一个全局属性。如果你到处都没有线程安全,那么你就不是线程安全期。如果您有许多读取器和读取操作,并且只有很少的编写器和写入操作,那么请考虑使用针对此类方案优化的ReaderWriterLockSlim类。每次访问列表时都必须使用它。