Reputation: 1101
I have got the following code:
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;
}
Method Update
can be performed in two or more threads and I use lock
to prevent cuncurency problems with foo
. But I would like to lock only those Foo
that have similar Id
. For instance if one thread executes method Update
with Foo.Id = 1 and another thread executes Update
with Foo.Id = 2 then lock
is not needed and if two threads execute Update with two instances Foo
with the same Id
, lock
is needed. Is it possible to create a such lock?
Upvotes: 8
Views: 1189
Reputation: 1614
I know the question is very old, but in case someone stumbles upon this and has the same issue, take a look at AsyncKeyedLock which solves the problem. Note: I am the author of this library.
In case you're using asynchronous code you can use:
using (await _locker.LockAsync(myObject.Id))
{
...
}
or if you're using synchronous code:
using (_locker.Lock(myObject.Id))
{
...
}
Upvotes: 1
Reputation: 460108
You could use this class to get a lock object for every 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;
}
}
}
Then hold an instance of it in your class:
private MultiLockObjects<int> _idLocks = new MultiLockObjects<int>();
Usage is simple:
public void Update(Foo foo)
{
Object idLockObject = _idLocks[foo.Id];
lock (idLockObject)
{
UpdateFirstPart(foo.First);
UpdateSecondPart(foo.Second);
UpdateThirdPart(foo.Third);
}
}
Upvotes: 5
Reputation: 13676
You could use ConcurrentDictionary<TKey, TValue>
for storing your locks.
private static readonly ConcurrentDictionary<int, object> ThreadLockDict =
new ConcurrentDictionary<int, object>();
And use it in Update method:
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
}
}
Upvotes: 3
Reputation: 273244
You can just lock(foo)
when you're sure
foo
to lock onId
You can not lock on int Id
.
Alas I use different instances of Foo with the same Id
Then you could try a ConcurrentDictionary<int, object>
to store a different _locker per Id. But that adds some overhead, and the problem of cleaning up that Dictionary when you run it for longer periods.
Upvotes: 2