【发布时间】:2015-12-06 23:02:27
【问题描述】:
我正在通过 ASP.NET 构建一个基本的基于 Web 的聊天,它轮询托管在 Windows 服务中的 WCF 服务。我对在多线程应用程序中管理共享资源还很陌生,所以我对我的方法中的线程安全有几个问题。
服务核心是一个名为 ServerManager 的 Singleton 类,它维护一个 ChatServer 对象字典,该字典仅被初始化和填充一次,并且永远不会再次添加或删除。来自 WCF 服务的调用将引用客户端“连接”到的实例的密钥 (serverID)。在任何给定时间,可能会有多个调用进入服务,多个线程同时调用 ServerManager 的方法。
对 Dictionary _servers 的访问与锁定块同步,同时获得对请求的 ChatServer 对象的引用,然后在锁定块之外使用本地引用。我不希望所有的 ChatServer 都被一个 ChatServer 的读/写阻塞。
在读取/写入 _messages 对象期间,我还在 ChatServer 实例中包含了同步。
在获取对所请求对象的引用时同步对 _servers 的访问是否是线程安全的,然后在锁定块之外使用该引用 (currentServer)?换句话说,只要访问这些对象中的共享数据是同步的,多个线程是否可以安全地访问 Dictionary 中的不同元素?
像在 ChatServer.GetNewMessages() 中那样将字符串列表返回给调用者是否是线程安全的?
如果 newMessages 是一些新 ChatMessage 对象的列表,我需要做些什么来确保 GetNewMessages 在返回 ChatMessage 列表时不会导致线程安全问题?
这是一个类的sn-p(注意:这个代码已经被简化以说明问题)
class ServerManager
{
private static readonly ServerManager _instance = new ServerManager();
private Dictionary<Int32, ChatServer> _servers = new Dictionary<Int32, ChatServer>();
private Object _lock = new Object();
private ServerManager()
{
_servers.Add(1, new ChatServer());
_servers.Add(2, new ChatServer());
_servers.Add(3, new ChatServer());
}
public static ServerManager Instance
{
get { return _instance; }
}
public void AddMessage(Int32 serverID, String message)
{
ChatServer currentServer;
lock (_lock)
{
currentServer = _servers[serverID];
}
currentServer.AddMessage(message);
}
public List<String> GetNewMessages(Int32 serverID)
{
ChatServer currentServer;
lock (_lock)
{
currentServer = _servers[serverID];
}
return currentServer.GetNewMessages();
}
}
class ChatServer
{
private List<String> _messages = new List<string>();
private Object _lock = new Object();
public ChatServer() { }
public void AddMessage(String message)
{
lock (_lock)
{
_messages.Add(message);
}
}
public List<String> GetNewMessages()
{
List<String> newMessages = new List<String>();
lock (_lock)
{
newMessages.AddRange(_messages);
}
return newMessages;
}
}
【问题讨论】:
-
不确定是否需要锁定字典以查找条目,如果您只是在初始化期间更改它,并且从不添加/删除条目。
-
看看ConcurrentDictionary,它将大大简化您的代码,并且您不需要所有这些锁。
-
你在哪里设置_lock = new object(); ?
-
我打算在声明中初始化 _lock,但是在进行代码编辑以将其发布到此处时,我在某处丢失了它。
-
可能要考虑
ImmutableDictionary<>
标签: c# multithreading wcf thread-safety