Runtime & concurrency
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Reflection;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
var sync = new object();
Console.WriteLine($"before:{Monitor.IsEntered(sync)}");
lock (sync) { lock (sync) { Console.WriteLine($"nested:{Monitor.IsEntered(sync)}"); } }
Console.WriteLine($"after:{Monitor.IsEntered(sync)}");
Reveal answer and reasoning
The lines are before:False, nested:True, and after:False. Before entry the current thread owns no monitor for sync. Both nested lock statements use that same object on the same thread, so reentrant entry succeeds and IsEntered is true inside. Exiting both scopes balances the entries, leaving the final check false. No other object or worker participates in this portable snippet.
The common wrong trace predicts a deadlock at the second lock by confusing reentrancy with competition by another thread. Another wrong answer keeps ownership after one scope while forgetting that both scopes exit before the final print. The external wrong-owner test is separate and does not add a line to this code. These observations prove the arranged ownership sequence, not fairness, cross-thread contention, or the safety of using a publicly shared lock object in an unrelated application.
What a strong answer covers
- Same-object same-thread nesting is reentrant.
- Both scopes exit before the final observation.
- The snippet creates no OS workers.
Common pitfall
Predicting same-thread deadlock or unbalanced final ownership in the nested lock statement.
Follow-up questions
- What would IsEntered report for another untouched object?
- What would a third nested scope change?
Self-review
Choose what to revisit. These marks are your own assessment and are separate from lesson completion.