线程同步笔记

在设计应用程序时,应该尽可能地避免进行线程同步。为此,要避免使用一些共享数据,比如静态字段。
线程用new操作符构造一个对象时,new操作符会返回对新对象的一个引用。在这个时刻,只有构造对象的线程
才有对它的引用;其他任何线程都不能访问那个对象。如果你能一直避免将这个引用传给可能同时使用对象的
另外一个线程,就不必同步对该对象的访问。
试着使用值类型,因为它们总是会被复制,所以每个线程操作的都是它自己的那个副本。
最后,多个线程同时对共享数据进行只读访问是没有任何问题的,例如,许多应用程序都会在它们初始化
期间创建一些数据结构。一旦初始化,应用程序就可以创建它希望的任何数量的线程;如果所有线程都只
是查询数据,那么所有线程都同时查询,无需获取或释放一个锁。String类型便是这样的一个例子:一旦
创建好String对象,它就是"不可变的"。所以,许多线程能同时访问一个string对象,string对象没有
破坏。
使一个方法线程安全,并不是说它一定要在内部获取一个线程同步锁。
一个线程安全的方法意味着在两个线程试图同时访问数据时,数据不会被破坏。
System.Math类一个静态max方法,它是像下面这样实现的:
public static Int32 Max(Int32 val1,Int32 val2)
{
retrun (val1<val2)? val2:val1;
}
这个方法是线程安全的,即使它没有获取任何锁。由于Int32是值类型,所以传给max的两个Int32值会复制到方法
内部。多个线程可以同时调用max方法,每个线程处理的都是它自己的数据,线程之间互不干扰。

一个线程构造一个对象时,只有这个线程才拥有对象引用,其他线程都不能访问那个对象,所以在调用
实例方法时无需线程同步。然而,如果线程随后公开了这个对象引用----把它放到一个静态字段中,
把它作为状态实参传给ThreadPool.QueueUserWorkItem或者传给一个Task----那么多个线程可能同时
进行非只读访问的前提下,就需要线程同步。

用户模式+内核模式:

/// <summary>
    /// 造成线程"自转",这个"自转"会浪费宝贵的cpu时间,阻止CPU做其他更有用的工作。
    /// 因此,自转锁只应用于保护那些会执行得非常快的代码区域。
/// 注意该类是值类型。
/// </summary> struct SimpleSpinLock { private Int32 _resourceInUse; public void Enter() { while(Interlocked.Exchange(ref _resourceInUse,1) !=0) { } } public void Leave() { Thread.VolatileWrite(ref _resourceInUse, 0); } } public sealed class SomeResource { private SimpleSpinLock sl = new SimpleSpinLock(); SpinLock sl2 = new SpinLock(); bool lockTaken = false; public void AccessResource() { sl2.Enter(ref lockTaken); sl2.Exit(); sl.Enter(); //一次只有一个线程才能进入这里。 sl.Leave(); } } sealed class SimpleHybridLock:IDisposable { private Int32 _waiters = 0; private AutoResetEvent _waiterLock = new AutoResetEvent(false); public void Enter() { if (Interlocked.Increment(ref _waiters) == 1) return; _waiterLock.WaitOne(); } public void Leave() { if (Interlocked.Decrement(ref _waiters) == 0) return; _waiterLock.Set(); } public void Dispose() { _waiterLock.Dispose(); } }

 

posted @ 2015-04-13 16:17  英雄饶命啊  阅读(182)  评论(0编辑  收藏  举报