Locking according to Id in async method

Viewed 1311

I have MVC application in which action methods must be executed on certain order. Recently, I am having some strange issues and I suppose that it is due to the fact that I do not do any thread synchronization. I have barely worked with multithreading and I don't know much about it. I tried to implement some kind of locking where I have to lock according to Id. So I implemented class like below to get required lock objects.

public class ReportLockProvider
    : IReportLockProvider
{
    readonly ConcurrentDictionary<long, object> lockDictionary 
        = new ConcurrentDictionary<long, object>();

    public object ProvideLockObject(long reportId)
    {
        return lockDictionary.GetOrAdd(reportId, new object());
    }
}

I tried to use this as below:

ReportLockProvider lockProvider = new ReportLockProvider();

public async ActionResult MyAction(long reportId)
{
    lock(lockProvider.ProvideLockObject(reportId))
    {
        // Some operations
        await Something();
        // Some operation
    }
}

I hoped that it would work, but it event didn't compiled because I have used await inside lock body. I have searched a bit and came across to SemaphoreSlim in this answer. Now, the problem is that I have to get lock object according to Id. How can I do this? Is it OK to create multiple SemaphoreSlim objects? Is it OK if I modify code like below :

public class ReportLockProvider
    : IReportLockProvider
{
    readonly ConcurrentDictionary<long, SemaphoreSlim> lockDictionary 
        = new ConcurrentDictionary<long, SemaphoreSlim>();

    public SemaphoreSlim ProvideLockObject(long reportId)
    {
        return lockDictionary.GetOrAdd(reportId, new SemaphoreSlim(1, 1));
    }
}


public async ActionResult MyAction(long reportId)
{
    var lockObject = ReportLockProvider.ProvideLockObject(reportId);

    await lockObject.WaitAsync();
    try
    {
        // Some operations
        await Something();
        // Some operation
    }
    finally
    {
        lockObject.Release();
    }
}

The other question is that, can I use SemaphoreSlim in non-async methods? Is there any better option?

1 Answers
Related