Does SemaphoreSlim (.NET) prevent same thread from entering block? : <p>I have read the docs for SemaphoreSlim <a href="https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&amp;l=EN-US&amp;k=k(System.Threading.SemaphoreSlim);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5.2);k(DevLang-csharp)&amp;rd=true" rel="noreferrer">SemaphoreSlim MSDN</a>
which indicates that the SemaphoreSlim will limit a section of code to be run by only 1 thread at a time if you configure it as:</p>

<pre><code>SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
</code></pre>

<p>However, it doesn't indicate if it stops the <strong>same</strong> thread from accessing that code.  This comes up with async and await.  If one uses await in a method, control leaves that method and returns when whatever task or thread has completed.  In my example, I use a button with an async button handler.  It calls another method (Function1) with 'await'.  Function1 in turn calls </p>

<pre><code>await Task.Run(() =&gt; Function2(beginCounter));
</code></pre>

<p>Around my Task.Run() I have a SemaphoreSlim.  It sure seems like it stops the same thread from getting to Function2.  But this is not guaranteed (as I read it) from the documentation and I wonder if that can be counted on.</p>

<p>I have posted my complete example below.</p>

<p>Thanks,</p>

<p>Dave</p>

<pre><code> using System;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Windows;

 namespace AsynchAwaitExample
 {
/// &lt;summary&gt;
/// Interaction logic for MainWindow.xaml
/// &lt;/summary&gt;
public partial class MainWindow : Window
{
    private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
    public MainWindow()
    {
        InitializeComponent();
    }

    static int beginCounter = 0;
    static int endCounter = 0;
    /// &lt;summary&gt;
    /// Suggest hitting button 3 times in rapid succession
    /// &lt;/summary&gt;
    /// &lt;param name="sender"&gt;&lt;/param&gt;
    /// &lt;param name="e"&gt;&lt;/param&gt;
    private async void button_Click(object sender, RoutedEventArgs e)
    {
        beginCounter++;
        endCounter++;
        // Notice that if you click fast, you'll get all the beginCounters first, then the endCounters
        Console.WriteLine("beginCounter: " + beginCounter + " threadId: " + Thread.CurrentThread.ManagedThreadId);
        await Function1(beginCounter);
        Console.WriteLine("endCounter: " + endCounter + " threadId: " + Thread.CurrentThread.ManagedThreadId);
    }

    private async Task Function1(int beginCounter)
    {
        try
        {
            Console.WriteLine("about to grab lock" + " threadId: " + Thread.CurrentThread.ManagedThreadId + " beginCounter: " + beginCounter);
            await _semaphoreSlim.WaitAsync();  // get rid of _semaphoreSlim calls and you'll get into beginning of Function2 3 times before exiting
            Console.WriteLine("grabbed lock" + " threadId: " + Thread.CurrentThread.ManagedThreadId + " beginCounter: " + beginCounter);
            await Task.Run(() =&gt; Function2(beginCounter));
        }
        finally
        {
            Console.WriteLine("about to release lock" + " threadId: " + Thread.CurrentThread.ManagedThreadId + " beginCounter: " + beginCounter);
            _semaphoreSlim.Release();
            Console.WriteLine("released lock" + " threadId: " + Thread.CurrentThread.ManagedThreadId + " beginCounter: " + beginCounter);
        }

    }

    private void Function2(int beginCounter)
    {
        Console.WriteLine("Function2 start" + " threadId: " + Thread.CurrentThread.ManagedThreadId + " beginCounter: " + beginCounter);
        Thread.Sleep(1000);
        Console.WriteLine("Function2 end" + " threadId: " + Thread.CurrentThread.ManagedThreadId + " beginCounter: " + beginCounter);
        return;
    }
}
}
</code></pre>

<p>Sample output if you click button 3 times.  Notice that Function2 always finishes for a given counter before it starts again.</p>

<pre><code>    beginCounter: 1 threadId: 9
about to grab lock threadId: 9 beginCounter: 1
grabbed lock threadId: 9 beginCounter: 1
Function2 start threadId: 13 beginCounter: 1
beginCounter: 2 threadId: 9
about to grab lock threadId: 9 beginCounter: 2
beginCounter: 3 threadId: 9
about to grab lock threadId: 9 beginCounter: 3
Function2 end threadId: 13 beginCounter: 1
about to release lock threadId: 9 beginCounter: 1
released lock threadId: 9 beginCounter: 1
grabbed lock threadId: 9 beginCounter: 2
Function2 start threadId: 13 beginCounter: 2
endCounter: 3 threadId: 9
Function2 end threadId: 13 beginCounter: 2
about to release lock threadId: 9 beginCounter: 2
released lock threadId: 9 beginCounter: 2
endCounter: 3 threadId: 9
grabbed lock threadId: 9 beginCounter: 3
Function2 start threadId: 13 beginCounter: 3
Function2 end threadId: 13 beginCounter: 3
about to release lock threadId: 9 beginCounter: 3
released lock threadId: 9 beginCounter: 3
endCounter: 3 threadId: 9
</code></pre>

<p>If you get rid of the SemaphoreSlim calls you'll get:</p>

<pre><code>beginCounter: 1 threadId: 10
about to grab lock threadId: 10 beginCounter: 1
grabbed lock threadId: 10 beginCounter: 1
Function2 start threadId: 13 beginCounter: 1
beginCounter: 2 threadId: 10
about to grab lock threadId: 10 beginCounter: 2
grabbed lock threadId: 10 beginCounter: 2
Function2 start threadId: 14 beginCounter: 2
beginCounter: 3 threadId: 10
about to grab lock threadId: 10 beginCounter: 3
grabbed lock threadId: 10 beginCounter: 3
Function2 start threadId: 15 beginCounter: 3
Function2 end threadId: 13 beginCounter: 1
about to release lock threadId: 10 beginCounter: 1
released lock threadId: 10 beginCounter: 1
endCounter: 3 threadId: 10
Function2 end threadId: 14 beginCounter: 2
about to release lock threadId: 10 beginCounter: 2
released lock threadId: 10 beginCounter: 2
endCounter: 3 threadId: 10
</code></pre>
