• c#中多线程同步Lock(锁)的研究以及跨线程UI的操作


    本文只针对C#中,多线程同步所用到的锁(lock)作为研究对象。由于想更直观的显示结果,所以,在做demo的时候,就把多线程通过事件操作UI的代码也写了出来,留作备忘和分享吧。

    其实多线程的同步,使用同步锁的方法用了好多次,今天无意中看到MSDN中,建议用:

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

    备注:原文并没有加readonly,是我后来自己加进去的。

    我不仅思考了一下他们的区别。

    然后我写了一段代码进行测试,测试类代码如下:

        /// <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种锁的区别:

            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();
                }
            }
    

      输出结果一模一样:

    得出结论:如果对一个实例,多线程访问的时候,2种锁是没有区别的。

    下面是测试多个实例的情况(静态锁):

            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);
            }

     

  • 相关阅读:
    POJ 2991 Crane(线段树)
    HDU 1754 I Hate It(线段树)
    HDU 1754 I Hate It(线段树)
    HDU 1166 敌兵布阵 (线段树模版题)
    HDU 1166 敌兵布阵 (线段树模版题)
    Tree Recovery
    Tree Recovery
    情人节的电灯泡(二维树状数组)
    情人节的电灯泡(二维树状数组)
    【LeetCode】Validate Binary Search Tree 二叉查找树的推断
  • 原文地址:https://www.cnblogs.com/tommyheng/p/4104552.html
Copyright © 2020-2023  润新知