csname1910
csname1910

Reputation: 1235

Locking async task c#

public class MyDbContext : DbContext
{
    ....

    static readonly object lockObject = new object();

    public override int SaveChanges()
    {
        lock (lockObject)
            return base.SaveChanges();
    }

    public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        lock (lockObject)
            return base.SaveChangesAsync(cancellationToken);
    }       
}

I want to use DbContext in multiple threads, but the underlying database has a problem if two threads are writing at the same time. So I am using lockObject to prevent two SaveChanges() at the same time.

That works fine in SaveChanges(), but I don't know how to do the same in SaveChangesAsync(). I think the solution above is wrong. How can I apply the lock to SaveChangesAsync?

Thank you!

Upvotes: 5

Views: 554

Answers (1)

Ive
Ive

Reputation: 1331

From https://blog.cdemi.io/async-waiting-inside-c-sharp-locks/ you can use:

public class MyDbContext 
{
    static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1);

    public override int SaveChanges()
    {
        semaphoreSlim.Wait();
        try
        {
            return base.SaveChanges();
        }
        finally
        {
            //When the task is ready, release the semaphore. It is vital to ALWAYS release the semaphore when we are ready, or else we will end up with a Semaphore that is forever locked.
            //This is why it is important to do the Release within a try...finally clause; program execution may crash or take a different path, this way you are guaranteed execution
            semaphoreSlim.Release();
        }
    }

    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        await semaphoreSlim.WaitAsync(cancellationToken);
        try
        {
            return await base.SaveChangesAsync();
        }
        finally
        {
            //When the task is ready, release the semaphore. It is vital to ALWAYS release the semaphore when we are ready, or else we will end up with a Semaphore that is forever locked.
            //This is why it is important to do the Release within a try...finally clause; program execution may crash or take a different path, this way you are guaranteed execution
            semaphoreSlim.Release();
        }
    }
}

Upvotes: 6

Related Questions