【发布时间】:2020-11-04 20:12:03
【问题描述】:
我有这样的代码:
public ConcurrentDictionary<Guid, DeviceItem> deviceStatesCache = new ConcurrentDictionary<Guid, DeviceItem>();
private readonly object deviceStatesCacheLock = new object();
public void StoreDeviceStateInCache(Guid guid, DeviceItem deviceState)
{
bool added, removed, updated = false;
lock (deviceStatesCacheLock)
{
added = deviceStatesCache.TryAdd(guid, deviceState);
if (!added) {
removed = deviceStatesCache.TryRemove(guid, out var _);
if (removed)
{
updated = deviceStatesCache.TryAdd(guid, deviceState);
}
}
}
if (!updated)
throw new Exception("WTF: cannot update deviceStatesCache!");
}
private QueryDevicesResponse CreateQueryDevicesResponse()
{
var deviceItems = new List<DeviceItem>();
lock (deviceStatesCacheLock)
{
foreach (var item in deviceStatesCache)
{
deviceItems.Add(item.Value);
}
}
var response = new QueryDevicesResponse()
{
eventData = new QueryDevicesResponse.EventData()
{
devices = deviceItems
}
};
// response.eventSourceGuid = Guid.Empty.ToString();
return response;
}
(编辑)
我的lock 应该在以下情况下工作:
-
当另一个线程尝试在
StoreDeviceStateInCache方法中的删除和插入之间获取值时(只有这个)。 -
当另一个线程开始读取
CreateQueryDevicesResponse()方法中的所有项目时。
我可以简化一下StoreDeviceStateInCache() 方法吗?
我知道存在 AddOrUpdate 方法,但我觉得它没有帮助,因为我必须定义额外的方法,而且这看起来比我的代码可读性差。
看起来Michael Liu suggestion 和deviceStatesCache[guid] = deviceState; 应该足够了
我可以稍微简化CreateQueryDevicesResponse() 方法并“原子地”阅读完整的字典吗?
(当然,WTF 代表“多么可怕的失败”类型的例外)
【问题讨论】:
-
请准确说明您的操作应该做什么,以及您的目标是哪种线程安全。
-
简化代码的一种方法是将
ConcurrentDictionary替换为普通的Dictionary。如果您必须锁定 anyConcurrentDictionary的成员,那么您必须锁定 all 他们(否则它将不是线程安全的) .在这种情况下,ConcurrentDictionary的所有优点都消失了,而你只剩下它的缺点(不方便的 API 和同步开销)。
标签: c# .net concurrentdictionary