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的异步编程;
            //那效果,整的是杠杠的,效果是非常好滴呀;

        }

好了就到这里;。

 

 

posted @ 2017-09-02 19:51  咕-咚  阅读(7200)  评论(1编辑  收藏  举报