我有以下代码:
public void Update(Foo foo)
{
lock(_locker)
{
UpdateFirstPart(foo.First);
UpdateSecondPart(foo.Second);
UpdateThirdPart(foo.Third);
}
}
public class Foo
{
public int Id;
public Some1 First;
public Some2 Second;
public Some3 Third;
}
方法Update
可以在两个或多个线程中执行,我使用lock
来防止foo
出现问题。但我想只锁定那些Foo
相似的Id
。例如,如果一个线程使用Foo.Id = 1执行方法Update
而另一个线程使用Foo.Id = 2执行Update
,则不需要lock
,如果两个线程执行带有两个的更新需要具有相同Foo
,Id
的实例lock
。是否可以创建这样的锁?
答案 0 :(得分:3)
您可以使用此类为每个Id获取一个锁定对象:
public class MultiLockObjects<TKey>
{
private readonly ConcurrentDictionary<TKey, Object> _multiLocker = new ConcurrentDictionary<TKey, Object>();
public Object this[TKey key]
{
get
{
Object lockObj = _multiLocker.GetOrAdd(key, tKey => new Object());
return lockObj;
}
}
}
然后在你的班级中保留一个实例:
private MultiLockObjects<int> _idLocks = new MultiLockObjects<int>();
用法很简单:
public void Update(Foo foo)
{
Object idLockObject = _idLocks[foo.Id];
lock (idLockObject)
{
UpdateFirstPart(foo.First);
UpdateSecondPart(foo.Second);
UpdateThirdPart(foo.Third);
}
}
答案 1 :(得分:3)
您可以使用ConcurrentDictionary<TKey, TValue>
存储锁。
private static readonly ConcurrentDictionary<int, object> ThreadLockDict =
new ConcurrentDictionary<int, object>();
并在Update方法中使用它:
public static void Update(Foo foo)
{
// add a new locker object for each foo if it's not already in dictionary
ThreadLockDict.TryAdd(foo.Id, new object());
lock (ThreadLockDict[foo.Id])
{
// some code
}
}
答案 2 :(得分:2)
当您确定
时,您可以lock(foo)
foo
锁定Id
您无法锁定int Id
。
唉,我使用不同的Foo实例和相同的Id
然后你可以尝试ConcurrentDictionary<int, object>
为每个Id存储不同的_locker。但是这会增加一些开销,以及在运行较长时间后清理该词典的问题。