9

I would like to compile a list of all possible conditions making Monitor go to kernel-mode or use a kernel sync object.

The sync block has a field to reference the kernel object. Hence I deducted that lock will go to kernel-mode sometimes.

I found this: Lock (Monitor) internal implementation in .NET

But it has too many questions to be answered and the only useful information is that the OP answered his own question by simply stating that the lock will go to the kernel-mode sometimes. Also there aren’t any links to anything to support that answer.

When exactly will lock go to kernel-mode (not if and not why - when)?

I am more interested to hear about .NET 4 and 4.5 if there is any difference with older versions.

From the Richter book: "A sync block contains fields for a kernel object, the owning thread’s ID, a recursion count, and a waiting threads count."

Zoe
  • 27,060
  • 21
  • 118
  • 148
Boppity Bop
  • 9,613
  • 13
  • 72
  • 151
  • Stop rolling back constructive edits. Editing is a core part of the site; see https://stackoverflow.com/help/editing – Zoe Jun 02 '22 at 16:10

3 Answers3

23

Most of these kind of questions can be answered by looking at the CLR source code as available through the SSCLI20 distribution. It is getting pretty dated by now. It is .NET 2.0 vintage, but a lot of the core CLR features haven't changed much.

The source code file you want to look at is clr/src/vm/syncblk.cpp. Three classes play a role here. AwareLock is the low-level lock implementation that takes care of acquiring the lock, SyncBlock is the class that implements the queue of threads that are waiting to enter a lock, and CLREvent is the wrapper for the operating system synchronization object, the one you are asking about.

This is C++ code and the level of abstraction is quite high. This code heavily interacts with the garbage collector and there's a lot of testing code included. So I'll give a brief description of the process.

SyncBlock has the m_Monitor member that stores the AwareLock instance. SyncBlock::Enter() directly calls AwareLock::Enter(). It first tries to acquire the lock as cheaply as possible. First checking if the thread already owns the lock and just incrementing the lock count if that's the case. Next using FastInterlockCompareExchange(), an internal function that's very similar to Interlocked.CompareExchange(). If the lock is not contended then this succeeds very quickly and Monitor.Enter() returns. If not then another thread already owns the lock, and AwareLock::EnterEpilog is used. There's a need to get the operating system's thread scheduler involved so a CLREvent is used. It is dynamically created if necessary and its WaitOne() method is called. Which will involve a kernel transition.

So there is enough to answer your question: the Monitor class enters kernel mode when the lock is contended and the thread has to wait.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • thank you very much. especially for the SSCLI - I didnt know this was available publicly. – Boppity Bop Feb 17 '13 at 17:11
  • 4
    Thanks for the comment which pointed me to relevant part in CLR source. I am specifically interested in spinning part: it is commonly claimed Monitor at first spins before going to kernel. And I am interested how exactly it spins (number of iterations, ...). I cannot see spinning in code path you have described, however, I see spinning logic there in AwareLock::Contention called by AwareLock::TryEnter. Now it seems, that this only applies for TryEnter when timeout is used, so I guess spinning is not used when using c# lock keyword. Am I right? – Martin Pozor Dec 10 '13 at 17:42
4

When the lock is heavily contended.

If the lock is lightly contended, there is a quick CPU spinlock to wait for the lock to be free again, but if this doesn't wait long enough for the lock to be free, the thread will blocking wait on the mutex, which involves a kernel mode call to suspend the thread and other such management.

Puppy
  • 144,682
  • 38
  • 256
  • 465
0

After its spinwait step, additional intelligence may exist, such as skipping spinwait on single core machines since the contested lock could only be released after releasing the thread.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Andrew Arnott
  • 80,040
  • 26
  • 132
  • 171
  • Andrew I need to have all the steps in plane view to see how this answers the question. Your answer is like - when people die if struck by a lightning - when they are dead. – Boppity Bop Feb 17 '13 at 16:29
  • @BoppityBop: Go get yourself a plane and an airstrip, then we discuss this point – Lightness Races in Orbit Feb 17 '13 at 16:49
  • Ya. If you want something more precise, how about "at 5:04:02.008"? Seriously, an absolute answer is useless, and a relative answer varies. The only thing left is a logical answer. After the previous step is completed, your question lacks a point that you're after. Why do you care? If you provided that, we might be able to provide a more useful answer. – Andrew Arnott Feb 17 '13 at 17:13