1) 用户模式,硬件提供支持,速度非常快,但是在 block 的时候消耗 CPU 资源,在未争 用的时候不损失性能
2) 内核模式,操作系统提供支持,速度比较慢,但是很灵活(比如可以设定超时时间, 可以等待一组同步结构都可用的时候继续)并且和用户模式想法的是在 block 的时候可以 不消耗 CPU
直接上代码,进行比较;
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication12 { struct SimpleSpinLock { private Int32 m_ResourceInUse; public void Enter() { while (Interlocked.Exchange(ref m_ResourceInUse, 1) != 0) { //循环 } } public void Leave() { Thread.VolatileWrite(ref m_ResourceInUse, 0); } } class SimpleWaitLock : IDisposable { private AutoResetEvent m_ResourceFree = new AutoResetEvent(true); public void Enter() { m_ResourceFree.WaitOne(); } public void Leave() { m_ResourceFree.Set(); } public void Dispose() { m_ResourceFree.Close(); } } //在来比较一些lock的方式呢; class Program { static object locker = new object(); static void Test() { Int32 x = 0; const Int32 iterations = 5000000; Stopwatch sw = Stopwatch.StartNew(); SimpleSpinLock ssl = new SimpleSpinLock(); for (Int32 i = 0; i < iterations; i++) { ssl.Enter(); x++; ssl.Leave(); //不断获取 和 离开 } Console.WriteLine("Incrementing x in SimpleSpinLock:{0:N0}", sw.ElapsedMilliseconds); using (SimpleWaitLock swl = new SimpleWaitLock()) { sw = Stopwatch.StartNew(); for (Int32 i = 0; i < iterations; i++) { swl.Enter(); x++; swl.Leave(); } Console.WriteLine("Incrementing x in SimpleWaitLock:{0:N0}", sw.ElapsedMilliseconds); } //lock方式的比较 已确保原子性的操作; sw = Stopwatch.StartNew(); for (Int32 i = 0; i < iterations; i++) { lock (locker) { x++; } //这个在单线程的模式下 进行的比较 } Console.WriteLine("Incrementing x in lock:{0:N0}", sw.ElapsedMilliseconds); } static void Main(string[] args) { Thread.Sleep(3000); Console.WriteLine("start..."); Test();//结果表明基于内核模式的同步比基于用户模式的同步慢了数十倍 } } }
然后直接看结果;
lock 在这里比较的意义不大;在这种情况下lock的效率可定是最高的。请记住是在这种情况下;
Volatile 两个作用一是防止编译器 JIT 甚至 CPU 对代码和指令等进行优化(比如跳过判断,调整代 码次序),二是防止多核 CPU 分别在自己的寄存器中缓存了值导致的不一致性,让值始终 从内存中读取。
Interlocked Interlocked.Exchange 和 Interlocked.CompareExchange 分别用于确保赋值操作和 比较赋值操作的原子性,值得一提的是,Interlocked.Exchange 并没有提供 bool 重载, 我们可以使用 int 的 0 和 1 替代。还有,Interlocked.Read 只提供了 long 重载,那是因 为读一个 long值的任何操作在 32 位操作系统上不是原子行为,而在 64位操作系统上 long 的读操作是原子的。
这个只是一个初步的了解,后面,会再花点时间来讨论和研究这个东东;