C#使用Monitor類、Lock和Mutex類進行多線程同步

來源:互聯網
上載者:User
    在多線程中,為了使資料保持一致性必須要對資料或是訪問資料的函數加鎖,在資料庫中這是很常見的,但是在程式中由於大部分都是單線程的程式,所以沒有加鎖的必要,但是在多線程中,為了保持資料的同步,一定要加鎖,好在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++)            {                mutex.WaitOne();                TestFunc("Thread2 have run " + count.ToString() + " times");                mutex.ReleaseMutex();            }        }        private void TestFunc(string str)        {            Console.WriteLine("{0} {1}", str, System.DateTime.Now.Millisecond.ToString());            Thread.Sleep(50);        }運行結果如下:         可以看出,Mutex只能互斥線程間的調用,但是不能互斥本線程的重複調用,即thread1中waitOne()只對thread2中的waitOne()起到互斥的作用,但是thread1並不受本wainOne()的影響,可以調用多次,只是在調用結束後調用相同次數的ReleaseMutex()就可以了。        那麼如何使線程按照調用順序來依次執行呢?其實把lock和Mutex結合起來使用就可以了,改代碼如下:        private void thread1Func()        {            for (int count = 0; count < 10; count++)            {                lock (this)                {                    mutex.WaitOne();                    TestFunc("Thread1 have run " + count.ToString() + " times");                    mutex.ReleaseMutex();                }            }        }        private void thread2Func()        {            for (int count = 0; count < 10; count++)            {                lock (this)                {                    mutex.WaitOne();                    TestFunc("Thread2 have run " + count.ToString() + " times");                    mutex.ReleaseMutex();                }            }        }
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.