程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#中使用Monitor類、Lock和Mutex類來同步多線程的執行

C#中使用Monitor類、Lock和Mutex類來同步多線程的執行

編輯:C#入門知識

在多線程中,為了使數據保持一致性必須要對數據或是訪問數據的函數加鎖,在數據庫中這是很常見的,但是在程序中由於大部分都是單線程的程序,所以沒有加鎖的必要,但是在多線程中,為了保持數據的同步,一定要加鎖,好在Framework中已經為我們提供了三個加鎖的機制,分別是Monitor類、Lock關鍵字和Mutex類。
        其中Lock關鍵詞用法比較簡單,Monitor類和Lock的用法差不多。這兩個都是鎖定數據或是鎖定被調用的函數。而Mutex則多用於鎖定多線程間的同步調用。簡單的說,Monitor和Lock多用於鎖定被調用端,而Mutex則多用鎖定調用端。
例如下面程序:由於這種程序都是毫秒級的,所以運行下面的程序可能在不同的機器上有不同的結果,在同一台機器上不同時刻運行也有不同的結果,我的測試環境為vs2005, windowsXp , CPU3.0 , 1 G monery。
        程序中有兩個線程thread1、thread2和一個TestFunc函數,TestFunc會打印出調用它的線程名和調用的時間(mm級的),兩個線程分別以30mm和100mm來調用TestFunc這個函數。TestFunc執行的時間為50mm。程序如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace MonitorLockMutex
{
    class Program
    {
        #region variable
        Thread thread1 = null;
        Thread thread2 = null;
        Mutex mutex = null;
        #endregion
        static void Main(string[] args)
        {
            Program p = new Program();
            p.RunThread();
            Console.ReadLine();
        }
        public Program()
        {
            mutex = new Mutex();
            thread1 = new Thread(new ThreadStart(thread1Func));
            thread2 = new Thread(new ThreadStart(thread2Func));
        }
        public void RunThread()
        {
            thread1.Start();
            thread2.Start();
        }
        private void thread1Func()
        {
            for (int count = 0; count < 10; count++)
            {
                TestFunc("Thread1 have run " + count.ToString() + " times");
                Thread.Sleep(30);
            }
        }
        private void thread2Func()
        {
            for (int count = 0; count < 10; count++)
            {
                TestFunc("Thread2 have run " + count.ToString() + " times");
                Thread.Sleep(100);
            }
        }
        private void TestFunc(string str)
        {
            Console.WriteLine("{0} {1}", str, System.DateTime.Now.Millisecond.ToString());
            Thread.Sleep(50);
        }
    }
}
運行結果如下:

        可以看出如果不加鎖的話,這兩個線程基本上是按照各自的時間間隔+TestFunc的執行時間(50mm)對TestFunc函數進行讀取。因為線程在開始時需要分配內存,所以第0次的調用不准確,從第1~9次的調用可以看出,thread1的執行間隔約是80mm,thread2的執行間隔約是150mm。
現在將TestFunc修改如下:
private void TestFunc(string str)
{
   lock (this)
   {
      Console.WriteLine("{0} {1}", str, System.DateTime.Now.Millisecond.ToString());
      Thread.Sleep(50);
   }
}
或者是用Monitor也是一樣的,如下:
private void TestFunc(string str)
{
      Monitor.Enter(this);
      Console.WriteLine("{0} {1}", str, System.DateTime.Now.Millisecond.ToString());
      Thread.Sleep(50);
      Monitor.Exit(this);
}
其中Enter和Exit都是Monitor中的靜態方法。
運行Lock結果如下:         讓我們分析一下結果,同樣從第1次開始。相同線程間的調用時間間隔為線程執行時間+TestFunc調用時間,不同線程間的調用時間間隔為TestFunc調用時間。例如:連續兩次調用thread1之間的時間間隔約為30+50=80;連續兩次調用thread2之間的時間間隔約為100+50=150mm。調用thread1和thread2之間的時間間隔為50mm。因為TestFunc被lock住了,所以一個thread調用TestFunc後,當其它的線程也同時調用TestFunc時,後來的線程即進被排到等待隊列中等待,直到擁有訪問權的線程釋放這個資源為止。
        這就是鎖定被調用函數的特性,即只能保證每次被一個線程調用,線程優先級高的調用的次數就多,低的就少,這就是所謂的強占式。
        下面讓我們看看Mutex類的使用方法,以及與Monitor和Lock的區別。
將代碼修改如下:
        private void thread1Func()
        {
            for (int count = 0; count < 10; count++)
            {
                mutex.WaitOne();
                TestFunc("Thread1 have run " + count.ToString() + " times");
                mutex.ReleaseMutex();
            }
        }

        private void thread2Func()
        {
            for (int count = 0; count < 10; count++)
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved