How to lock objects withthe same ids?

别说谁变了你拦得住时间么 提交于 2020-06-25 09:43:07

问题


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?


回答1:


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
    }
}



回答2:


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);
    }
}



回答3:


You can just lock(foo) when you're sure

  • no other code is using foo to lock on
  • reference equality (identity) is acceptable/usable, this is not using Id

You can not lock on int Id.


Part 2,

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.



来源:https://stackoverflow.com/questions/46888590/how-to-lock-objects-withthe-same-ids

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!