zoukankan      html  css  js  c++  java
  • c# 线程的等待(堵塞)

    这里我要强调一个概念,

     多线程是多线程,

    异步编程是异步编程

    这两个是有区别的概念;

    我可以说多线程天生就要异步的特点;但你不能说多线程成就等同于我们的异步编程;

    根不能说异步编程就是我们的多线程。这里不要搞混淆了;

    再net中的进化如下:

    多线程:Thread =>ThreadPool=> Task

    异步编程:BenginInvokeXXX EndInvokeXXX IAsyncResult=> async await (这里面配合着Task的使用)(基于任务的异步模式 (TAP) 时来使用异步操作)

    好接下来,再来总结我们的线程(任务)的等待。

    总结:

    方法一:Thread.Sleep(),这个要预估,等待的时间应该大于我们的子线程执行的时间。

    方法二:当然就是我们最常用的Join() 方法了,堵塞当前调用子线程成的方法,直到我们的子线程执行完毕。

    方法二:主线程轮训子线程(这个是基于我们的IasyncResult 编程模式的,及时传说中的beginxxxx  endxxxx这种模式)

    方法三:采用通知的方法就是我们的EevntWaitHanld = new AutoRestEevnt(false),然后waitOne 和 Set 的方式来进行的,效果非常好滴呀;

    方法四:我把它命名为偏方:就是利用独占锁的机制,当子线程用完锁之后,释放,让给我们的主线程,前提是要确保我们的子线程先得到锁;

    方法五:这个就是基于我们的Task的wait方法;

    这里我给出一些,练习的demo,仅供参考使用;

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication13
    {
        //我们把它叫做等待子线程,或者,等待子线程一定的时间;
        //最原始的是使用 waitEevnt的方法;我们甚至可以用 poll的方式;
        //还有基于事件编程的回调方式;
    
        
        public class Person
        {
    
        }
        class Program
        {
            //evnet wait handle
            //该方法也可以用来进行线程的同步滴呀;
            public static object locker = new object();
            public static EventWaitHandle handler = new AutoResetEvent(false);
    
            public static void Eat()
            {
                Thread.Sleep(3000);
            }
    
            public static void Eat_WithSet()
            {
                Thread.Sleep(3000);
    
                handler.Set(); //子线程发出做完实行的信号;
            }
    
            public static void Eat_WithLock()
            {
                Console.WriteLine("枷锁开始");
                lock (locker)
                {
                    Thread.Sleep(3000);   //假设,我们这里有很多的是事情要做的呀;
                    //效果非常好;
                }
                Console.WriteLine("枷锁释放");
            }
    
            public static void Eat_Loop()
            {
    
                for (int i = 0; i < 10; i++)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine("");
                }
    
            }
    
            //那么这个方法就不能为空了
    
            public static  void Eat_Wait()
            {
                for (int i = 0; i < 10; i++)
                {
                    Task.Delay(1000).Wait();
                    Console.WriteLine("");
                }
    
            }
    
            public static void TestJoin()
            {
    
                Console.WriteLine("main start");
    
                Thread thread = new Thread(Eat);
                thread.Start();
                //给我等着;
                Console.WriteLine("主线程先做点其他事情;");
                //这我们我们可以直接用线程自带的方法;
                thread.Join();
                Console.WriteLine("好了,子线程事情做完了..");
                Console.WriteLine("main end");
                Console.ReadLine();
    
            }
    
            public static void Test_Set()
            {
    
                Console.WriteLine("main start");
    
                Thread thread = new Thread(Eat_WithSet);
                thread.Start();
                //给我等着;
                Console.WriteLine("主线程先做点其他事情;");
                handler.WaitOne();
                Console.WriteLine("好了,子线程事情做完了..");
                Console.WriteLine("main end");
                Console.ReadLine();
    
            }
    
            public static void Test11()
            {
    
                Console.WriteLine("main start");
    
                Thread thread = new Thread(Eat_WithSet);
                thread.Start();
                //给我等着;
                Console.WriteLine("主线程先做点其他事情;");
                handler.WaitOne(TimeSpan.FromSeconds(3));
    
                //注意这里,一点 waitone 和 task.wait 如果都指定了 等待的时间;
                //如果子线程在指定的时间内没有做完时间,那么我们就开始了主线程的方法;
                //这里并没有真正的取消线程;
                //问题又来了,如果去取消子线程呢;这个......
    
                Console.WriteLine("好了,不堵塞,主线程了,");
                Console.WriteLine("main end");
                Console.ReadLine();
    
            }
            //偏方
            public static void Test_Lock()
            {
    
                Console.WriteLine("main start");
                Thread thread = new Thread(Eat_WithLock);
                thread.Start();
                //给我等着;
                Console.WriteLine("主线程先做点其他事情;");
                
                //如果是单线层的话,我还是使用一点偏方;
                //那就是我们的lock方法滴呀;
                Thread.Sleep(20);//为了让子线程得到锁,我们这里估计sleep一下了
                //所以尼玛的叫偏方了;
                lock (locker)
                {
                    //当然这种方式,就是完全出去一种四等的状态;
                    //等待另外一个线程释放锁;
                    Console.WriteLine("这个表示我们的另外一个线程执行完毕了;");
                }
                Console.ReadLine();
    
            }
    
            //如果要取消原来的方法的话,还得到原来的的方法去操作,整的是麻烦的一件事情;
            //不过有我们的Task 就方便多;;
    
            public static void Test_Task()
            {
                //task的取消就相对简单的多了;
                Console.WriteLine("main start");
                Task task = Task.Run(()=>Eat_Wait());
    
                Console.WriteLine("mian do something.then wait task");
    
               // task.Wait();  //默认情况下,它会等待task执行完毕;
    
                task.Wait(TimeSpan.FromSeconds(3));//在这里只能等待三秒,三秒只有,就不堵塞我们的主线程;
                //这里这的注意的事情是,等待不等于取消哦;
                //这一点是相对非常关键的啦;
    
                //先一节我们再来略略线程的取消啦滴呀;
    
                Console.WriteLine("task completed...");
    
                Console.WriteLine("main end");
    
                Console.ReadLine();
    
            }
    
       
            static void Main(string[] args)
            {
    
                //Test();
                //Test1();
                //Test11();
                //Test_Lock();
                //Test_Task();
    
            }
        }
    }

    //这里我再来演示一个set 之后,通知多个线程的实例,或则理解成为广播是似的传递消息;

    或则:多个线程在等待某一个线程的信号;

      to do 

     线程只有不断的去判断他的isalive属性;

    异步编程则可以使用的轮训的回调的方式;  如果你的主线程一直等待,那么 尼玛的就叫异步编程了;

            public static void Test_IsAlive()
            {
    
                //Eat_Loop
                Console.WriteLine("main start");
    
                Thread thread = new Thread(Eat_Loop);
                thread.Start();
                Console.WriteLine("mian do something.then wait task");
    
                while (thread.IsAlive)
                {
                    Thread.Sleep(100);
                    Console.WriteLine("子线程还在zuoshiser");
                }
    
                Console.WriteLine("子线程把事儿做完了!");
    
                Console.WriteLine("mian end");
            }
    
            public static int CountInfo(int x)
            {
                Thread.Sleep(5000);
                return x+100;
            }
    
            public static void Test_IsComplete()
            {
                //异步编程了
                Func<int, int> fn = CountInfo;
                IAsyncResult actionResult = fn.BeginInvoke(100, CountInfoCallback, null); //既没有回调,也没有参数这样的方法不太正常;
    
               while (!actionResult.IsCompleted)
               {
                   Thread.Sleep(100);
                   Console.WriteLine("子线程还在zuoshiser");
               }
                //做完之后 记得endinvoke;
                int result= fn.EndInvoke(actionResult);
                //这样就可以得到我们的结果;
    
               //在这里结束,也可以在回调方法中结束 endInvoek;
    
    
            }
    
            static void CountInfoCallback(IAsyncResult iar)
            {
                Console.WriteLine("这里是回调....");
    
                AsyncResult ar = (AsyncResult)iar;
    
                Func<int, int> del = (Func<int, int>)ar.AsyncDelegate;
                var result = del.EndInvoke(iar);
    
                //总的的来说,就是我们的采用回调和轮训的两种方式;
                //来实现我们的异步编程的实现;
                //不过好在,现在我们又了 async 和await 基于task的异步编程;
                //那效果,整的是杠杠的,效果是非常好滴呀;
    
            }

    好了就到这里;。

     

  • 相关阅读:
    Node Js
    动态遍历接收的参数
    负载均衡和springcloud.Ribbon
    Spring Cloud
    springboot整合hibernate
    python模块知识总结
    什么是netty--通俗易懂
    IDEA 的操作与使用
    spring 整合guava
    log4j向指定文件输出日志
  • 原文地址:https://www.cnblogs.com/mc67/p/7467550.html
Copyright © 2011-2022 走看看