带着问题去思考!你们好。
今天咱们来了解下什么是线程同步?安全
首先咱们先知道这些概念和一些类;多线程
咱们都知道确保当一个线程使用某些资源的时候,同时其余线程没法使用该资源。这引入一个概念是共享资源。ide
多个线程同时使用共享对象会形成不少问题。同步线程使得对共享对象的操做可以以正确的顺序执行是很是重要的。spa
首先经过一个加减例子了解下lock处理操作系统
public abstract class CounterBase { public abstract void Increment(); public abstract void Decrement(); } public class Counter:CounterBase { public int Count { get;private set; } public override void Decrement() { Count++; } public override void Increment() { Count--; } } public class CounterLock : CounterBase { private readonly object _synclock = new object(); public int Count { get; private set; } public override void Decrement() { lock(_synclock) { Count++; } } public override void Increment() { lock (_synclock) { Count--; } } } static void Main(string[] args) { #region 多线程锁 Console.WriteLine("Incorrect counter"); var c = new Counter(); var t1 = new Thread(() => TestCount(c)); var t2= new Thread(() => TestCount(c)); var t3 = new Thread(() => TestCount(c)); t1.Start(); t2.Start(); t3.Start(); t1.Join(); t2.Join(); t3.Join(); Console.WriteLine("Total count:{0}",c.Count); Console.WriteLine("-----------"); Console.WriteLine("Correct counter"); var c1 = new CounterLock(); t1 = new Thread(() => TestCount(c1)); t2 = new Thread(() => TestCount(c1)); t3 = new Thread(() => TestCount(c1)); t1.Start(); t2.Start(); t3.Start(); t1.Join(); t2.Join(); t3.Join(); Console.WriteLine("Total count:{0}", c1.Count); #endregion } static void TestCount(CounterBase c) { for (int i = 0; i < 1000; i++) { c.Increment(); c.Decrement(); } }
咱们知道,最终结果应该是0;线程
由于第一个线程获得count为10增长为11,第二个线程获得的值是11并增长为12.第一个线程获得count为12,可是递减操做发生前,第二个线程获得的值也是12,。而后第一个线程将12递减11并保存count中,同时第二个线程进行了一样的操做,结果咱们进行了两次递增操做可是只有一次递减操做。这是竞争条件(race condition)code
1:请尽可能避免使用共享对象对象
2:必须是共享的状态时候,使用原子操做。一个操做只占一个量子的时间,一次完成。这说明只有当前操做完成后,其余线程才能执行其余操做,避免死锁,和使用锁blog
3:使用不一样方式来协调线程资源
执行基本的原子操做
不用阻塞线程就可避免竞争条件
public class CounterLock : CounterBase { public int Count { get; private set; } public int _count; public override void Decrement() { Interlocked.Decrement(ref _count); } public override void Increment() { Interlocked.Increment(ref _count); } }
咱们修改CounterLock,再来看看结果
咱们可能会获得0,可是最终会获得一些不肯定的非0.第一个例子是线程不安全的。第二个例子中,咱们借助Interlocked类,无需锁定任何对象便可获取正确结果。Interlocked提供了Increment.Decrement和Add基于数学操做的原子方法,编写Counter类时无需使用锁、
Mutex类
const string MutexName = "CSharpThreadingCookbook"; static void Main(string[] args) { using (var m=new Mutex(false,MutexName)) { if(!m.WaitOne(TimeSpan.FromSeconds(5),false)) { Console.WriteLine("Second instance is running!"); } else { Console.WriteLine("Running!"); Console.ReadLine(); m.ReleaseMutex(); } } }
程序启动,定义一个指定名称的互斥量,设置initialOwner标志为false,这意味着若是互斥量已经被建立,则容许程序获取该互斥量。若是没有得到互斥量,程序则简单显示Running
在运行一样一个程序,则会在5秒种内尝试得到互斥量,若是此时在第一个程序中按下任意键,第二个程序则会开始执行。然而若是保持等待5秒,第二个程序没法得到该互斥量