How to prevent a method from running across multiple threads?

Viewed 13252

I am working on a web application, where several users can update the same record. So to avoid a problem if users are updating the same record at the same time, I am saving their changes in a queue. When each save occurs, I want to call a method that processes the queue on another thread, but I need to make sure that the method cannot run in another thread if it is called again. I’ve read several posts on the subject, but not sure what is best for my situation. Below is the code I have now. Is this the correct way to handle it?

public static class Queue {
    static volatile bool isProcessing;
    static volatile object locker = new Object();

    public static void Process() {
        lock (locker) {
            if (!isProcessing) {
                isProcessing = true;

                //Process Queue...

                isProcessing = false;
            }
        }
    }
}
2 Answers

A lock is good but it won't work for async await. You will get the following error if you try to await a method call in a lock:

CS1996 Cannot await in the body of a lock statement

In this case you should use a SemaphoreSlim

Example:

public class TestModel : PageModel
{
    private readonly ILogger<TestModel> _logger;
    private static readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);

    public TestModel(ILogger<TestModel> logger)
    {
        _logger = logger;
    }

    public async Task OnGet()
    {
        await _semaphoreSlim.WaitAsync();
        try
        {
            await Stuff();
        }
        finally
        {
            _semaphoreSlim.Release();
        }
    }
}

It is important to not new SemaphoreSlim in the constructor or anywhere else because then it won't work.

https://stackoverflow.com/a/18257065/3850405

https://docs.microsoft.com/en-us/dotnet/api/system.threading.semaphoreslim?view=net-5.0

Related