













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 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 is waiting. There is contention, block this thread
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 blocked, just return
// Other threads are blocked, wake 1 of them
m_waiterLock.Set(); // Bad performance hit here.
}
}
internal sealed class AnotherHybridLock : 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 AutoResetEvent m_waiterLock = new AutoResetEvent(false);
// This field controls spinning in an effort to improve performance
private Int32 m_spinCount = 4000; // Arbitrarily chosen count
// These fields indicate which thread owns the lock and how many times it owns it
private Int32 m_owningThreadId = 0, m_recursion = 0;
public void Enter() {
// If calling thread already owns the lock, increment recursion count and return
Int32 threadId = Thread.CurrentThread.ManagedThreadId;
if (threadId == m_owningThreadId) {
m_recursion++;
return;
}
// The calling thread doesn't own the lock, try to get it
SpinWait spinwait = new SpinWait();
for (Int32 spinCount = 0; spinCount < m_spinCount; spinCount++) {
// If the lock was free, this thread got it; set some state and return
if (Interlocked.CompareExchange(ref m_waiters, 1, 0) == 0)
goto GotLock;
// Black magic: give other threads a chance to run
// in hopes that the lock will be released
spinWait.SpinOnce();
}
// Spinning is over and the lock was still not obtained, try one more time
if (Interlocked.Increment(ref m_waiters) > 1) {
// Other threads are blocked and this thread must block too
m_waiterLock.WaitOne(); // Wait for the lock; preformance hit
// When this thread wakes, it owns the lock; set some state and return
}
GotLock:
// When a thread gets the lock, we record its ID and
// indicate that the thread owns the lock once
m_owningThreadId = threadId;
m_recursion = 1;
}
public void Leave() {
// If the calling thread doesn't own the lock, there is a bug
Int32 threadId = Thread.CurrentThread.ManagedThreadId;
if (threadId != m_owningThreadId)
throw new SynchronizationLockException("Lock not owned by calling thread");
// Decrement the recursion count. If this thread still owns the lock, just return
if (--m_recursion > 0)
return;
// If no other threads are blocked, just return
if (Interlocked.Decrement(ref m_waiters) == 0)
return;
// Other threads are bloced, wake 1 of them
m_waiterLock.Set(); // Bad performance hit here
}
}
Incrementing x: 8 Fastest
Incrementing x in Mutex: 50 6x slower
Incrementing x in SimpleSpinLock: 210 26x slower
Incrementing x in SimpleHybridLock: 211 26x slower (similar to SimpleSpinLock)
Incrementing x in AnotherHybridLock: 415 52x slower (due to ownership/recursion)
Incrementing x in SimpleWaitLock: 17,615 2,201x slower
private readonly Object m_lock = new Object();
...
Monitor.Enter(m_lock);
...
Monitor.Exit(m_lock);
; // Broken multithreaded version
// "Double-Checked Locking" idiom
class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null)
synchronized(this) {
if (helper == null)
helper = new Helper();
}
return helper;
}
// other functions and members...
}
简单的办法,使用静态字段:
class HelperSingleton {
static Helper singleton = new Helper();
}
或者,使用JDK5的新语法,volatile关键字:
// Works with acquire/release semantics for volatile
// Broken under current semantics for volatile
class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null)
helper = new Helper();
}
}
return helper;
}
}
internal sealed class Singleton {
private static readonly Object s_lock = new Object();
private static Singleton s_value = null;
private Singleton() {
}
public static Singleton GetSingleton() {
if (s_value != null) return s_value;
Monitor.Enter(s_lock);
if (s_value == null) {
Singleton temp = new Singleton();
Interlocked.Exchange(ref s_value, temp);
}
Monitor.Exit(s_lock);
return s_value;
}
}
internal sealed class Singleton {
private static Singleton s_value = new Singleton();
private Singleton() {
}
public static Singleton GetSingleton() { return s_value; }
}
因为CLR在代码第一次尝试访问类的成员时,会自动调用类型的类构造器(class initializer, type initializer, static initializer)。线程第一次调用Singleton.GetSingletonk静态方法时,CLR自动调用类构造器(注意Before-Field-Init语义),创建出一个该对象的实例。并且:CLR保证调用类型构造器是线程安全的。 internal sealed class Singleton {
private static Singleton s_value = null;
private Singleton() {
}
public static Singleton GetSingleton() {
if (s_value != null) return s_value;
Singleton temp = new Singleton();
Interlocked.CompareExchange(ref s_value, temp, null);
return s_value;
}
}
internal sealed class ConditionVariablePattern {
private readonly Object m_lock = new Object();
private Boolean m_condition = false;
public void Thread1() {
Monitor.Enter(m_lock);
while (!m_condition) {
Monitor.Wait(m_lock);
}
Monitor.Exit(m_lock);
}
public void Thread2() {
Monitor.Enter(m_lock);
m_condition = true;
Monitor.PulseAll(m_lock);
Monitor.Exit(m_lock);
}
}
internal sealed class SynchronizedQueue<T> {
private readonly Object m_lock = new Object();
private readonly Queue<T> m_queue = new Queue<T>();
public void Enqueue(T item) {
Monitor.Enter(m_lock);
m_queue.Enqueue(item);
// After enqueuing an item, wake up any/all waiters;
Monitor.PulseAll(m_lock);
Monitor.Exit(m_lock);
}
public T Dequeue() {
Monitor.Enter(m_lock);
while (m_queue.Count == 0)
Monitor.Wait(lock);
T item = m_queue.Dequeue();
Monitor.Exit(m_lock);
return item;
}
}
本章讲述的是混合的线程同步模式,首先通过一个简单的例子演示了如何混合使用用户模式和核心模式的同步结构。然后说明了轮转、线程所有制、锁递归的概念。接着列举了几种混合同步结构的实例,并进行了分析比较。本章还讨论了一个非常有意思的问题:单例模式的两次检查加锁情况,给出了正确实现单例模式的方法。然后讲了什么是条件变量模式,以及如何通过使用集合、Task和线程池来避免长时间持有锁。最后简单说明了四个并发集合类。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。