Monitor.TryEnter(o) and variants with timeout 0 are as special case that is purely opportunistic and should fail fast and not do any spinning.
1M TryEnter(o)s on a locked object will currently take over 3 minutes.
Remarks from MSDN Monitor.TryEnter Method (Object)
If successful, this method acquires an exclusive lock on the obj parameter. This method returns immediately, whether or not the lock is available.
This method is similar to Enter, but it will never block the current thread. If the thread cannot enter without blocking, the method returns false,.
Emphasis mine 😉 Technically it doesn't block/suspend; but its not as opportunistic with resources as it should be.
Consider the following code (Server GC, 4 core machine)
public class Program
{
private const int iters = 1000 * 1000;
public static void Main(string[] args)
{
var o = new object();
var s = new SemaphoreSlim(0);
Task.Run(() =>
{
Monitor.Enter(o);
s.Release();
Thread.Sleep(240000);
Monitor.Exit(o);
});
s.Wait();
var sw = Stopwatch.StartNew();
for (var i = 0; i < 1000; i++)
{
Monitor.TryEnter(o, 0);
}
sw.Stop();
Console.WriteLine($"Warmup 1000 iters {sw.Elapsed.TotalMilliseconds}ms");
GC.Collect();
sw.Restart();
for (var i = 0; i < iters; i++)
{
Monitor.TryEnter(o);
}
sw.Stop();
Console.WriteLine($"Main {iters} iters {sw.Elapsed.TotalMilliseconds}ms");
Console.ReadLine();
}
This will output something similar to the following and consume a full cpu core during the execution
Warmup 1000 iters 220.6732ms
Main 1000000 iters 219587.2351ms
Which means 1M iterations of a 0 timeout TryEnter when blocked will take 3 mins 39 secs to complete and burn an entire cpu during the full time.
Contrast to
SpinLock TryEnter(0, ref) which currently consumes 24ms (down to 5.95ms after dotnet/coreclr#6944)
SemaphoreSlim where Wait(0) and WaitAsync(0) take 12ms and 24ms respectively dotnet/coreclr#6898 (comment)
Monitor.TryEnter(o)and variants with timeout 0 are as special case that is purely opportunistic and should fail fast and not do any spinning.1M
TryEnter(o)s on a locked object will currently take over 3 minutes.Remarks from MSDN Monitor.TryEnter Method (Object)
Emphasis mine 😉 Technically it doesn't block/suspend; but its not as opportunistic with resources as it should be.
Consider the following code (Server GC, 4 core machine)
This will output something similar to the following and consume a full cpu core during the execution
Which means 1M iterations of a 0 timeout
TryEnterwhen blocked will take 3 mins 39 secs to complete and burn an entire cpu during the full time.Contrast to
SpinLockTryEnter(0, ref)which currently consumes 24ms (down to 5.95ms after dotnet/coreclr#6944)SemaphoreSlimwhereWait(0)andWaitAsync(0)take 12ms and 24ms respectively dotnet/coreclr#6898 (comment)