c#如何创建线程安全的二维锁集合
本文关键字:集合 二维 线程 何创建 创建 安全 | 更新日期: 2023-09-27 18:29:39
我正在尝试实现一个线程安全的二维集合,以控制对多个资源的访问。从我所看到的问题来看,我需要在集合级别(这很简单)和单个对象级别执行锁定,但不一定同时执行这两个级别,这可能会导致一些问题。
public class LockStore
{
private object _syncLock = new object();
private Dictionary<string, StoredLock> _locks = new Dictionary<string, StoredLock>();
public StoredLock GetOrAdd(string id, StoredLock lockDetails)
{
if (!_locks.ContainsKey(id))
lock (_syncLock)
{
if (!_locks.ContainsKey(id))
_locks.Add(id, lockDetails);
}
return _locks[id];
}
public void Remove(string id)
{
lock (_syncLock)
{
_locks.Remove(id);
}
}
}
public class StoredLock
{
public string Id { get; set; }
public DateTime CreatedDateTime { get; set; }
}
例如,线程可以调用LockStore.GetOrAdd()方法,返回StoredLock对象。然后,我想锁定StoreLock对象,以防止其他线程能够访问它,但不需要为整个字典持有锁。
var id = "someId"
var storedLock = lockStore.GetOrAdd(id, new StoredLock());
lock (storedLock)
{
//Do something
}
在一个完全不同的线索中的某个时刻。。。
lockStore.Remove(id);
当在存储在LockStore中的StoredLock对象上获取锁时,该锁不是为LockStore持有的,因此理论上可以为该特定Id调用LockStore.Remove(),因为Remove()方法不了解它实际包含的对象上持有的锁。我不确定在这种情况下会发生什么,但我认为这不好!
此外,我认为这可能会违反用于锁定的对象不能公开访问的设计原则?
我真的对此感到不知所措,所以任何关于解决问题或实际方法的建议都将不胜感激。
EDIT:特别具体地说,我不想同时锁定LockStore集合和单个StoredLock,因为这会大大减慢处理速度。
在理解了这个问题之后,我认为你应该做这样的事情:
public class LockStore
{
private readonly Dictionary<string, StoredLock> m_Dictionary =
new Dictionary<string, StoredLock>();
public void UseResource(string resource_id, Action<StoredLock> action)
{
StoredLock stored_lock = null;
lock(m_Dictionary)
{
if (m_Dictionary.ContainsKey(resource_id))
{
stored_lock = m_Dictionary[resource_id];
}
else
{
stored_lock = new StoredLock
{
Id = resource_id,
CreatedDateTime = DateTime.Now
};
m_Dictionary.Add(resource_id,stored_lock);
}
}
lock(stored_lock)
{
action(stored_lock);
}
}
public bool RemoveLock(string resource_id)
{
lock (m_Dictionary)
{
if (!m_Dictionary.ContainsKey(resource_id))
return true;
var stored_lock = m_Dictionary[resource_id];
bool taken = false;
Monitor.TryEnter(stored_lock, ref taken);
if (!taken)
return false;
try
{
m_Dictionary.Remove(resource_id);
}
finally
{
Monitor.Exit(stored_lock);
}
return true;
}
}
}
这段代码设计得并不完美,但它确实有效。你应该努力让它变得更好。
基本上,这个类允许您从线程1:中执行类似的操作
lockStore.UseResource("resource1", sl =>
{
//Do some processing with s1
});
从线程2:做这样的事情
var removed = lockStore.RemoveLock("resource1");
如果某个线程仍持有对象的锁,则RemoveLock
将立即返回并给您返回值false
。