.Net线程同步 come from: http://hi.baidu.com/lieyu063/blog/item/76713f466583cb086a63e53c.html

Lock关键字

 

说明:1, Lock关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁

            2, 通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。常见的结构 lock (this)lock (typeof (MyType))lock ("myLock") 违反此准则。最佳做法是定义 private 对象来锁定。

namespace 线程同步
{
     class Account
     {
         private Object thisLock = new Object();   //作为锁
         int balance;

         Random r = new Random();

         public Account(int initial)
         {
             balance = initial;
         }

         int Withdraw(int amount)
         {

             // This condition will never be true unless the lock statement
             // is commented out:
             if (balance < 0)
             {
                 throw new Exception("Negative Balance");
             }

             //注释掉lock就可能出问题
             lock (thisLock)
             {
                 if (balance >= amount)   //如果 余额 >= 提款额
                 {
                     Console.WriteLine("提款前的余额 :   " + balance);
                     Console.WriteLine("提款额         : -" + amount);
                     balance = balance - amount;
                     Console.WriteLine("提款后的余额   :   " + balance);
                     Console.WriteLine("");
                     return amount;
                 }
                 else
                 {
                     return 0; // transaction rejected
                 }
             }
         }

         public void DoTransactions()
         {
             for (int i = 0; i < 100; i++)
             {  
                 Withdraw(r.Next(1, 100));
             }
         }
     }

     class Test
     {
         static void Main()
         {
             Thread[] threads = new Thread[10];

             Account acc = new Account(1000); //新建一个帐户,存款1000
             for (int i = 0; i < 10; i++)
             {
                 Thread t = new Thread(new ThreadStart(acc.DoTransactions)); //新建10个线程进行取款
                 threads[i] = t;
             }

             for (int i = 0; i < 10; i++)
             {
                 threads[i].Start();   //线程开始取款
             }
         }
     }
}

ManualResetEvent

 

class Program
     {
         /// <summary>
         /// ManualResetEvent建立时是把false作为start的初始状态,这个类用于通知另一个线程,让它等待一个或多个线程。
         /// 如这个例子中,等待线程thread1线程调用mre.WaitOne(), 用于发信号的线程调用mre.Set().
         /// </summary>
         public static ManualResetEvent mre = new ManualResetEvent(false);

         public static void trmain()
         {

             Thread tr = Thread.CurrentThread;

             Console.WriteLine(tr.Name + " 开始第一波等待");
            mre.WaitOne();   //等到什么时候呢?等到mre.Set()被调用
             Console.WriteLine(tr.Name + " 第一波启动t");

            mre.Reset();   //再次重置
             Console.WriteLine(tr.Name + " 开始第二波等待");
            mre.WaitOne();   //再次等待
             Console.WriteLine(tr.Name + " 第二波启动");

             for (int x = 0; x < 10; x++)
             {

                 Thread.Sleep(1000);
                 Console.WriteLine(tr.Name + ": " + x);
             }
         }  


         static void Main(string[] args)
         {
             Thread thrd1 = new Thread(new ThreadStart(trmain));
             thrd1.Name = "thread1";
             thrd1.Start();

             Thread thrd2 = new Thread(new ThreadStart(trmain));
             thrd2.Name = "thread2";
             thrd2.Start();

             for (int x = 0; x < 10; x++)
             {
                 Thread.Sleep(900);
                 Console.WriteLine("Main :" + x);
                 if (5 == x)
                 {
                    mre.Set();   //子线程的mre.WaitOne()可以执行了。第一次等待进程
                     //;   //如果什么都不做呢,mre.Wait()那个线程就一直等在那里了?
                 }
             }

             while (thrd1.IsAlive)
             {

                 Thread.Sleep(1000);

                 Console.WriteLine("Main: waiting for thread to stop...");
                mre.Set();   //第二次通知等待进程
             }


         }
     }

 

Interlocked类

 

说明:Interlocked 为多个线程共享的变量提供原子操作。 Interlocked 类提供这样一些方法,即同步对多个线程共享的变量的访问的方法。如果该变量位于共享内存中,则不同进程的线程就可以使用该机制。互锁操作是原子的 — 即整个操作是不能由相同变量上的另一个互锁操作所中断的单元。在现代处理器中,Interlocked 类的方法经常可以由单个指令来实现。因此,它们提供性能非常高的同步,并且可用于构建更高级的同步机制,例如自旋锁。

Exchange 已重载。 以原子操作的形式将变量设置为指定的值。返回原始值。可用来对锁进行操作

class InterlocakedTest
       {
           //0 for false, 1 for true.
           private static int usingResource = 0;

           private static Object currentMso;
           private static Object globalMso = new Object(); //全局资源
           private const int numThreadIterations = 5;
           private const int numThreads = 10;

           static void Main()
           {
               Thread myThread;
               Random rnd = new Random();

               for(int i = 0; i < numThreads; i++)
               {
                   myThread = new Thread(new ThreadStart(MyThreadProc));
                   myThread.Name = String.Format("Thread{0}", i + 1);
            
                   //Wait a random amount of time before starting next thread.
                   Thread.Sleep(rnd.Next(0, 1000));
                   myThread.Start();
               }
           }

           private static void MyThreadProc()
           {
               //for(int i = 0; i < numThreadIterations; i++)
               //{
                   UseResource();
            
                   //Wait 1 second before next attempt.
                   Thread.Sleep(1000);
               //}
           }

           //A simple method that denies reentrancy.
           static bool UseResource()
           {
               //0 indicates that the method is not in use.把它置为1。如果返回的原始值是0。代表获得锁
               if(0 == Interlocked.Exchange(ref usingResource, 1))     //获得锁
               {
                   Console.WriteLine("{0} 获得锁", Thread.CurrentThread.Name);
            
                   //Code to access a resource that is not thread safe would go here.
            
                   //Simulate some work
                   Thread.Sleep(500);

                   Console.WriteLine("{0} 退出锁", Thread.CurrentThread.Name);
            
                   //Release the lock
                Interlocked.Exchange(ref usingResource, 0); //解锁
                   return true;
               }
               else
               {
                   Console.WriteLine("      {0} 被拒绝", Thread.CurrentThread.Name);
                   return false;
               }
           }
       }

说明:Interlocked.Increment 以原子操作的形式递增指定变量的值并存储结果。

          Interlocked.Decrement 以原子操作的形式递减指定变量的值并存储结果。

namespace 线程同步
{
      class InterlockedTest2
      {

          static void Main()
          {
              Thread thread1 = new Thread(new ThreadStart(ThreadMethod));
              Thread thread2 = new Thread(new ThreadStart(ThreadMethod));
              thread1.Start();
              thread2.Start();

              thread1.Join();
              thread2.Join();

              // Have the garbage collector run the finalizer for each
              // instance of CountClass and wait for it to finish.
              GC.Collect();
              GC.WaitForPendingFinalizers();

              Console.WriteLine("UnsafeInstanceCount: {0}" +
                  "/nSafeCountInstances: {1}",
                  CountClass.UnsafeInstanceCount.ToString(),
                  CountClass.SafeInstanceCount.ToString());
          }

          static void ThreadMethod()
          {
              CountClass cClass;

              // Create 100,000 instances of CountClass.
              for (int i = 0; i < 100000; i++)
              {
                  cClass = new CountClass();
              }
          }
      }

      //unsafeInstanceCount,safeInstanceCount是类变量,所以两个线程对它的访问要保证是原子的。
      class CountClass
      {
          static int unsafeInstanceCount = 0;
          static int safeInstanceCount = 0;

          static public int UnsafeInstanceCount
          {
              get { return unsafeInstanceCount; }
          }

          static public int SafeInstanceCount
          {
              get { return safeInstanceCount; }
          }

          public CountClass()
          {
              unsafeInstanceCount++;
              Interlocked.Increment(ref safeInstanceCount);
          }

          ~CountClass()
          {
              unsafeInstanceCount--;
              Interlocked.Decrement(ref safeInstanceCount);
          }
      }


}

Monitor监视器类

 

说明: 1,     Monitor 对象通过使用 Monitor.Enter、Monitor.TryEnter 和 Monitor.Exit 方法对特定对象获取锁和释放锁来公开同步访问代码区域的能力。(这点看,Lock的代码区域类似用Monitor.Enter和Monitor.Exit内的代码段)在对代码区域获取锁后,就可以使用 Monitor.Wait、Monitor.Pulse 和 Monitor.PulseAll 方法了。如果锁被暂挂,则 Wait 释放该锁并等待通知。当 Wait 接到通知后,它将返回并再次获取该锁。Pulse 和 PulseAll 都会发出信号以便等待队列中的下一个线程继续执行。

               2,  Monitor 将锁定对象(即引用类型),(Lock可以获取值类型的锁吗?应该也不可以吧而非值类型。尽管可以向 Enter 和 Exit 传递值类型,但对于每次调用它都是分别装箱的。因为每次调用都创建一个独立的对象,所以 Enter 永远不会阻止,而且它要保护的代码并没有真正同步。

              3,    注意到 Monitor 和 WaitHandle 对象在使用上的区别是非常重要的。Monitor 对象是完全托管、完全可移植的,并且在操作系统资源要求方面可能更为有效。WaitHandle 对象表示操作系统可等待对象,对于在托管和非托管代码之间进行同步非常有用,并公开一些高级操作系统功能。

          **4.    Monitor.enter     就是lock{     ;而Monitor.exit     就是lock     结束}   
                  lock     (对象){     //     就是Monitor.enter(对象)   
    
                  }     //就是Monitor.exit     .
                 在lock结束之前所有线程对该对象的操作都将被强制睡眠直到解锁。
                 但要特别注意的是     Monitor     有更强大的功能,比如     Monitor.TryEnter。Monitor.TryEnter方法就是获取对象的排它锁是否成功。Monitor.TryEnter无论有没有获取对象锁都会返回结果。Monitor.TryEnter在没有锁对象的情况下进行等待,而lock就处于等待直到完成。在执行过程方法或对象是所有线程唯的,那只好用lock;如果线程对锁操作可以放弃或者有别的选择的情况可以采用Monitor.TryEnter。

using System;
using System.Threading;

// Note: The class whose internal public member is the synchronizing
// method is not public; none of the client code takes a lock on the
// Resource object.The member of the nonpublic class takes the lock on
// itself. Written this way, malicious code cannot take a lock on
// a public object.(这个类的写法,可以防止恶意代码在public对象加锁)
public class SyncResource
{
     public void Access(Int32 threadNum)
     {
         // Uses Monitor class to enforce synchronization.
         lock (this)
         {
             // Synchronized: Despite the next conditional, each thread
             // waits on its predecessor.
             if (threadNum % 2 == 0)
                 Thread.Sleep(2000);

             Console.WriteLine("Start Synched Resource access (Thread={0})", threadNum);
             Thread.Sleep(200);
             Console.WriteLine("Stop Synched Resource access (Thread={0})", threadNum);
         }
     }
}

// Without the lock, the method is called in the order in which threads reach it.
public class UnSyncResource
{
     public void Access(Int32 threadNum)
     {
         // Does not use Monitor class to enforce synchronization.
         // The next call throws the thread order.
         if (threadNum % 2 == 0)
             Thread.Sleep(2000);
         Console.WriteLine("Start UnSynched Resource access (Thread={0})", threadNum);
         Thread.Sleep(200);
         Console.WriteLine("Stop UnSynched Resource access (Thread={0})", threadNum);
     }
}

public class App
{
     public static object obj = new object();

     static Int32 numAsyncOps = 5;
     static AutoResetEvent asyncOpsAreDone = new AutoResetEvent(false);

     static SyncResource SyncRes = new SyncResource();
     static UnSyncResource UnSyncRes = new UnSyncResource();

     public static void Main()
     {

         for (Int32 threadNum = 5; threadNum > 0; threadNum--)
         {
             ThreadPool.QueueUserWorkItem(new WaitCallback(SyncUpdateResource), threadNum);
         }

         // Wait until this WaitHandle is signaled.
         asyncOpsAreDone.WaitOne();
         Console.WriteLine("/t/nAll synchronized operations have completed./t/n");

         // Reset the thread count for unsynchronized calls.
         numAsyncOps = 5;

         for (Int32 threadNum = 0; threadNum < 5; threadNum++)
         {
             ThreadPool.QueueUserWorkItem(new WaitCallback(UnSyncUpdateResource), threadNum);
         }

         // Wait until this WaitHandle is signaled.
         asyncOpsAreDone.WaitOne();
         Console.WriteLine("/t/nAll unsynchronized thread operations have completed.");
     }


     // The callback method's signature MUST match that of a
     // System.Threading.TimerCallback delegate (it takes an Object
     // parameter and returns void).
     static void SyncUpdateResource(Object state)
     {
         // This calls the internal synchronized method, passing
         // a thread number.
         SyncRes.Access((Int32)state);

         // Count down the number of methods that the threads have called.
         // This must be synchronized, however; you cannot know which thread
         // will access the value **before** another thread's incremented
         // value has been stored into the variable.
         if (Interlocked.Decrement(ref numAsyncOps) == 0)
             asyncOpsAreDone.Set();
         // Announce to Main that in fact all thread calls are done.
     }

     // The callback method's signature MUST match that of a
     // System.Threading.TimerCallback delegate (it takes an Object
     // parameter and returns void).
     static void UnSyncUpdateResource(Object state)
     {
         // This calls the internal synchronized method, passing a thread number.
         UnSyncRes.Access((Int32)state);

         // Count down the number of methods that the threads have called.
         // This must be synchronized, however; you cannot know which thread
         // will access the value **before** another thread's incremented
         // value has been stored into the variable.
         if (Interlocked.Decrement(ref numAsyncOps) == 0)
             asyncOpsAreDone.Set();
         // Announce to Main that in fact all thread calls are done.
     }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值