Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to lock objects withthe same ids?

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?

like image 481
Pupkin Avatar asked Oct 23 '17 11:10

Pupkin


People also ask

What is object locking?

Object Lock can help prevent objects from being deleted or overwritten for a fixed amount of time or indefinitely. You can use Object Lock to help meet regulatory requirements that require WORM storage, or to simply add another layer of protection against object changes and deletion.

How do I lock an item in place?

Lock an object in placeSelect the Inspector from the toolbar. In the Inspector, select the Lock tab. Select an object (or objects) on the canvas that you would like to lock. Choose Lock.


2 Answers

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
    }
}
like image 150
Fabjan Avatar answered Oct 17 '22 14:10

Fabjan


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);
    }
}
like image 3
Tim Schmelter Avatar answered Oct 17 '22 15:10

Tim Schmelter