zoukankan      html  css  js  c++  java
  • C#多线程同步重新梳理

    线程同步这一方面,因为相对来说用得比较少,每次做多线程相关的问题是都必须重新温习,今天在看异步TCP时,又重新梳理了下。

    多线程同步大概有两类:一类是信号量,另一类是互斥,排他

    1.信号量

     

    实例代码如:

     class Program

        {
            private int n1, n2, n3;
            EventWaitHandle myEventWaitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);    //EventResetMode中有手动和自动设置信号量;

                    //false没默认没有信号,true表示默认有信号。对应的类AutoResetEvent和ManualResetEvent

            static void Main(string[] args)
            {
                Program p = new Program();
                Thread t0 = new Thread(new ThreadStart(p.WriteThread));
                Thread t1 = new Thread(new ThreadStart(p.ReadThread));
               
              
                t1.Start();
                t0.Start();
                Thread t3 = new Thread(new ThreadStart(p.AA));
                t3.Start();
                Console.ReadLine();
            }
            private void WriteThread() 
            {
                //允许其他需要等待的线程阻塞
                myEventWaitHandle.Reset();    //获得信号并让其他的wait处理等待状态
                Console.WriteLine("t1");
                n1 = 1; 
                n2 = 2;
                n3 = 3;
                myEventWaitHandle.Set();   //允许其他等待的线程继续
            }
            private void ReadThread()
            {
               
                myEventWaitHandle.WaitOne();    //阻塞当前线程,直到收到信号
                Console.WriteLine("{0}+{1}+{2}={3}", n1, n2, n3, n1 + n2 + n3);
            }
            private void AA() 
            {
                myEventWaitHandle.WaitOne();   //阻塞当前线程,直到收到信号
                string aa = "";
            }
       

    //AutoResetEvent和ManualResetEvent的区别是在waitone后,自动会变成无信号状态,而手动不会,如下面的实例如果设置成手动,则都可以执行,如果设置成

    自动, ReadThread和AA方法有一个方法执行不到,因为waitone在自动获得信号后变成了信号状态。

        }

     2.lock关键字

          lock是C#关键词,它将语句块标记为临界区,确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。方法是获取给定对象的互斥锁,执行语句,然后释放该锁。

          MSDN上给出了使用lock时的注意事项通常,应避免锁定 public 类型,否则实例将超出代码的控制范围

    3.Monitor类

     lock就是对Monitor的Enter和Exit的一个封装,而且使用起来更简洁,因此Monitor类的Enter()和Exit()方法的组合使用可以用lock关键字替代 

    另外Monitor类还有几个常用的方法:

          TryEnter()能够有效的解决长期死等的问题,如果在一个并发经常发生,而且持续时间长的环境中使用TryEnter,可以有效防止死锁或者长时间 的等待。比如我们可以设置一个等待时间bool gotLock = Monitor.TryEnter(myobject,1000),让当前线程在等待1000秒后根据返回的bool值来决定是否继续下面的操作。

          Wait()释放对象上的锁以便允许其他线程锁定和访问该对象。在其他线程访问对象时,调用线程将等待。脉冲信号用于通知等待线程有关对象状态的更改。

          Pulse(),PulseAll()向一个或多个等待线程发送信号。该信号通知等待线程锁定对象的状态已更改,并且锁的所有者准备释放该锁。等待线程被 放置在对象的就绪队列中以便它可以最后接收对象锁。一旦线程拥有了锁,它就可以检查对象的新状态以查看是否达到所需状态。

          注意:Pulse、PulseAll和Wait方法必须从同步的代码块内调用。

      class Program
        {
            private static object objA = new object();
            private static object objB = new object();
            static void Main(string[] args)
            {
                Thread threadA = new Thread(LockA);
                Thread threadB = new Thread(LockB);
                threadA.Start();
                threadB.Start();
                Thread.Sleep(4000);
                Console.WriteLine("线程结束");
                
                Console.ReadLine();
            }
            public static void LockA()
            {
                if (Monitor.TryEnter(objA, 1000))
                {
                    Thread.Sleep(1000);
                    if (Monitor.TryEnter(objB, 2000))
                    {
                        Monitor.Exit(objB);
                    }
                    else
                    {
                        Console.WriteLine("LockB timeout");
                    } 
                    Monitor.Exit(objA);
                }
                Console.WriteLine("LockA");
            }
            public static void LockB()
            {
                if (Monitor.TryEnter(objB, 2000))
                {
                    Thread.Sleep(2000);
                    if (Monitor.TryEnter(objA, 1000))
                    {
                        Monitor.Exit(objA);
                    }
                    else
                    {
                        Console.WriteLine("LockA timeout");
                    }
                    Monitor.Exit(objB);
                }
                Console.WriteLine("LockB");
            }
        }

     本来未产生死锁的,但什么有个超时时间,所以不会发生死锁

    4Mutex 

    EventWaitHandle的名字与Mutex差了很多,不过它可是Mutex不折不扣的兄弟——它和Mutex都是WaitHandle的子类,用法也差不多 

  • 相关阅读:
    asp.net 对母版页的控件事件
    treeview操作集合
    使用GAppProxy时安全证书无效的解决办法
    向Excel模板中添加数据
    C# 重写 winform 关闭按钮
    完整ASP.Net Excel导入程序(支持2007)
    随笔二则
    标记枚举(flags)的使用
    System.Reflection.Missing.Value与Type.Missing
    Windows下Android源码下载方法
  • 原文地址:https://www.cnblogs.com/fujinliang/p/2552841.html
Copyright © 2011-2022 走看看