c#中多線程同步Lock(鎖)的研究以及跨線程UI的操做

本文只針對C#中,多線程同步所用到的鎖(lock)做爲研究對象。因爲想更直觀的顯示結果,因此,在作demo的時候,就把多線程經過事件操做UI的代碼也寫了出來,留做備忘和分享吧。多線程

 

其實多線程的同步,使用同步鎖的方法用了好屢次,今天無心中看到MSDN中,建議用:併發

1 private static readonly object locker1 = new object();
2 private readonly object locker2 = new object();

備註:原文並無加readonly,是我後來本身加進去的。測試

我不只思考了一下他們的區別。this

而後我寫了一段代碼進行測試,測試類代碼以下:spa

    /// <summary>
    /// 跨線程操做UI的時候傳遞的參數,本文爲了顯示消息,因此簡單的封裝了一個
    /// </summary>
    public class MyEventArgs : EventArgs
    {
        public readonly string Message = string.Empty;
        public MyEventArgs(string msg)
        {
            this.Message = msg;
        }
    }
    /// <summary>
    /// 測試類,用於測試2種鎖的區別
    /// </summary>
    public class LockTest
    {
        //2個鎖
        private static readonly object Locker1 = new object();
        private readonly object Locker2 = new object();

        /// <summary>
        /// 跨線程操做UI的委託和事件
        /// </summary>
        public delegate void MessageEventHandler(object sender, MyEventArgs e);
        public event MessageEventHandler MessageEvent;
        public void OnMessage(MyEventArgs e)
        {
            if (this.MessageEvent != null) MessageEvent(this, e);
        }

        //要鎖的變量,經過它能夠看出2種鎖在不一樣狀況下的效果
        private int num = 0;
        //實例名字
        private readonly string Name;
        public LockTest(string name)
        {
            Name = name;
        }
        //第一種鎖執行的方法
        public void AddNum1()
        {
            lock (Locker1)
            {
                num = 0;
                ShowMessage();
            }
        }
        //第二種鎖執行的方法
        public void AddNum2()
        {
            lock (Locker2)
            {
                num = 0;
                ShowMessage();
            }
        }
        //鎖內的一些操做,並經過事件,把關鍵的消息顯示到主線程中的UI裏
        private void ShowMessage()
        {
            string msg = "";
            for (int i = 0; i < 10; i++)
            {
                num += 1;
                msg = string.Format("線程 [{0}],實例[{1}]中num的值是[{2}]", Thread.CurrentThread.Name, this.Name, num);
                OnMessage(new MyEventArgs(msg));
                Thread.Sleep(100);
            }
            msg = string.Format("======線程 [{0}]執行完畢======", Thread.CurrentThread.Name);
            OnMessage(new MyEventArgs(msg));
        }
    }

測試用的類寫完了,開始測試:線程

首先測試單個實例、多線程,2種鎖的區別:code

        private void button1_Click(object sender, EventArgs e)
        {
            LockTest test = new LockTest("LockTest 1");
            test.MessageEvent += new LockTest.MessageEventHandler(MessageCallBack);
            listBox1.Items.Clear();
            for (int i = 0; i <= 2; i++)
            {
                Thread a = new Thread(new ThreadStart(test.AddNum1));
                a.Name = i.ToString();
                a.Start();
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            LockTest test = new LockTest("LockTest 1");
            test.MessageEvent += new LockTest.MessageEventHandler(MessageCallBack);
            listBox1.Items.Clear();
            for (int i = 0; i <= 2; i++)
            {
                Thread a = new Thread(new ThreadStart(test.AddNum2));
                a.Name = i.ToString();
                a.Start();
            }
        }

  輸出結果如出一轍:

orm

得出結論:若是對一個實例,多線程訪問的時候,2種鎖是沒有區別的。對象

下面是測試多個實例的狀況(靜態鎖):blog

        private void button3_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear();
            for (int i = 0; i <= 2; i++)
            {
                LockTest test = new LockTest("LockTest " + i.ToString());
                test.MessageEvent += new LockTest.MessageEventHandler(MessageCallBack);
                Thread a = new Thread(new ThreadStart(test.AddNum1));
                a.Name = i.ToString();
                a.Start();
            }
        }

獲得結果:

得出結論,在靜態鎖面前,線程依舊要排隊,雖然不是一個實例,可是鎖是惟一的,線程只認鎖,因此線程並無併發!

繼續測試(非靜態的鎖):

        private void button4_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear();
            for (int i = 0; i <= 2; i++)
            {
                LockTest test = new LockTest("LockTest " + i.ToString());
                test.MessageEvent += new LockTest.MessageEventHandler(MessageCallBack);
                Thread a = new Thread(new ThreadStart(test.AddNum2));
                a.Name = i.ToString();
                a.Start();
            }
        }

獲得的結果:

得出結論:非靜態鎖的時候,多線程併發了,一塊兒在工做。

 

其實,測試的結果以前也能猜測出來,只不過,不測試下,內心老是以爲沒底,呵呵,測試完了,也就完全釋然了!

 

窗體中,用於事件回調,顯示到UI裏的代碼在這裏:

delegate void MessageHandler(string msg);
        public void MessageCallBack(object sender, MyEventArgs e)
        {
            MessageHandler handler = new MessageHandler(ShowMessage);
            this.Invoke(handler, new object[] { e.Message });
        }

        public void ShowMessage(string msg)
        {
            this.listBox1.Items.Add(msg);
        }
相關文章
相關標籤/搜索