How to ensure that part of code (which contains async) would be called only once? How to ensure that part of code (which contains async) would be called only once? multithreading multithreading

How to ensure that part of code (which contains async) would be called only once?


Put in the class:

private int entered = 0;

and in the method:

if (Interlocked.Increment(ref entered) != 1){    return;}

Only the first call to the method will be able to change entered from 0 to 1. The others will make it 2, 3, 4, 5...

Clearly you'll need something to reset the entered if you want your method to be refireable...

Interlocked.Exchange(ref entered, 0);

at the end of a successful call to the method.

Ah... and it isn't possible to use lock/Monitor.* around an await, because the current thread of the method can change, while nearly all the synchronization libraries expect that the thread you use to enter a lock is the same you use to exit the lock.

You can even use the Interlocked.CompareExchange()...

if (Interlocked.CompareExchange(ref entered, 1, 0) != 0){    return;}

The first thread to enter will be able to exchange the value of entered from 0 to 1, and it will receive the old value, 0 (so failing the if and continuing in the remaining code). The other threads will fail the CompareExchange and see the "current" value of 1, so entering the if and exiting the method


If you do want to restrict multiple threads using the same method concurrently then I would use the Semaphore class to facilitate the required thread limit; here's how...

A semaphore is like a mean night club bouncer, it has been provide a club capacity and is not allowed to exceed this limit. Once the club is full, no one else can enter... A queue builds up outside. Then as one person leaves another can enter (analogy thanks to J. Albahari).

A Semaphore with a value of one is equivalent to a Mutex or Lock except that the Semaphore has no owner so that it is thread ignorant. Any thread can call Release on a Semaphore whereas with a Mutex/Lock only the thread that obtained the Mutex/Lock can release it.

Now, for your case we are able to use Semaphores to limit concurrency and prevent too many threads from executing a particular piece of code at once. In the following example five threads try to enter a night club that only allows entry to three...

class BadAssClub{    static SemaphoreSlim sem = new SemaphoreSlim(3);    static void Main()    {        for (int i = 1; i <= 5; i++)             new Thread(Enter).Start(i);    }    // Enfore only three threads running this method at once.    static void Enter(int i)    {        try        {            Console.WriteLine(i + " wants to enter.");            sem.Wait();            Console.WriteLine(i + " is in!");            Thread.Sleep(1000 * (int)i);            Console.WriteLine(i + " is leaving...");        }        finally        {            sem.Release();        }    }}

Note, that SemaphoreSlim is a lighter weight version of the Semaphore class and incurs about a quarter of the overhead. it is sufficient for what you require.

I hope this helps.