Home Random Page


CATEGORIES:

BiologyChemistryConstructionCultureEcologyEconomyElectronicsFinanceGeographyHistoryInformaticsLawMathematicsMechanicsMedicineOtherPedagogyPhilosophyPhysicsPolicyPsychologySociologySportTourism






Nbsp;   A Simple Hybrid Lock

So, without further ado, let me start off by showing you an example of a hybrid thread synchroniza- tion lock.

 

internal sealed class SimpleHybridLock : IDisposable {

// The Int32 is used by the primitive user­mode constructs (Interlocked methods) private Int32 m_waiters = 0;

 

// The AutoResetEvent is the primitive kernel­mode construct

private readonly AutoResetEvent m_waiterLock = new AutoResetEvent(false);

 

public void Enter() {

// Indicate that this thread wants the lock

if (Interlocked.Increment(ref m_waiters) == 1)

return; // Lock was free, no contention, just return

 

// Another thread has the lock (contention), make this thread wait m_waiterLock.WaitOne(); // Bad performance hit here

// When WaitOne returns, this thread now has the lock

}

 

public void Leave() {

// This thread is releasing the lock

if (Interlocked.Decrement(ref m_waiters) == 0)

return; // No other threads are waiting, just return

 

// Other threads are waiting, wake 1 of them m_waiterLock.Set(); // Bad performance hit here

}

 

public void Dispose() { m_waiterLock.Dispose(); }

}

 

The SimpleHybridLock contains two fields: an Int32, which will be manipulated via the primi- tive user-mode constructs, and an AutoResetEvent, which is a primitive kernel-mode construct.

To get great performance, the lock tries to use the Int32 and avoid using the AutoResetEvent as much as possible. Just constructing a SimpleHybridLock object causes the AutoResetEvent to be created, and this is a massive performance hit compared to the overhead associated with the Int32 field. Later in this chapter, we’ll see another hybrid construct (AutoResetEventSlim) that avoids the performance hit of creating the AutoResetEvent until the first time contention is detected from multiple threads accessing the lock at the same time. The Dispose method closes the AutoReset­ Event, and this is also a big performance hit.

Although it would be nice to improve the performance of constructing and disposing of a SimpleHybridLock object, it would be better to focus on the performance of its Enter and Leave methods because these methods tend to be called many, many times over the object’s lifetime. Let’s focus on these methods now.


The first thread to call Enter causes Interlocked.Increment to add one to the m_waiters field, making its value 1. This thread sees that there were zero threads waiting for this lock, so the thread gets to return from its call to Enter. The thing to appreciate here is that the thread acquired the lock very quickly. Now, if another thread comes along and calls Enter, this second thread incre- ments m_waiters to 2 and sees that another thread has the lock, so this thread blocks by calling WaitOne using the AutoResetEvent. Calling WaitOne causes the thread to transition into the Windows’ kernel, and this is a big performance hit. However, the thread must stop running anyway, so it is not too bad to have a thread waste some time to stop completely. The good news is that the thread is now blocked, and so it is not wasting CPU time by spinning on the CPU, which is what the SimpleSpinLock’s Enter method, introduced in Chapter 29, does.



Now let’s look at the Leave method. When a thread calls Leave, Interlocked.Decrement is called to subtract 1 from the m_waiters field. If m_waiters is now 0, then no other threads are blocked inside a call to Enter and the thread calling Leave can simply return. Again, think about how fast this is: leaving a lock means that a thread subtracts 1 from an Int32, performs a quick if test, and then returns! On the other hand, if the thread calling Leave sees that m_waiters was not 1, then the thread knows that there is contention and that there is at least one other thread blocked in the kernel. This thread must wake up one (and only one) of the blocked threads. It does this by calling Set on AutoResetEvent. This is a performance hit, because the thread must transition into the ker- nel and back, but this transition occurs only when there was contention. Of course, AutoResetEvent ensures that only one blocked thread wakes up; any other threads blocked on the AutoResetEvent will continue to block until the newly unblocked thread eventually calls Leave.

       
   
 
 

 

 


Date: 2016-03-03; view: 882


<== previous page | next page ==>
Nbsp;   Kernel-Mode Constructs | Nbsp;   Spinning, Thread Ownership, and Recursion
doclecture.net - lectures - 2014-2024 year. Copyright infringement or personal data (0.007 sec.)