C# Thread挂起线程和恢复线程

前言

众所周知,Thread类中的挂起线程和恢复线程微软已标记过时,因为可能会造成问题

  Resume()   恢复当前线程

已过时。 Resumes a thread that has been suspended.

  Suspend()   挂起当前线程

已过时。 挂起线程,或者如果线程已挂起,则不起作用。

其他方式实现

一、ThreadWorkItem

  class ThreadWorkItem
    {
        public int ThreadManagerId { get; set; }
        public Thread Thread { get; set; }
        public string ThreadName { get; set; }
        public bool Flag { get; set; }
        public ManualResetEvent ManualResetEvent { get; set; }

    }

二、C# Thread挂起线程和恢复线程的实现的两种方式

方式1:使用变量开关控制挂起线程和恢复线程,具体代码如下

    public class Program
    {
        //线程工作集合
        private static List<ThreadWorkItem> Works = new List<ThreadWorkItem>();

        //方式1:使用变量开关控制挂起线程和恢复线程

        private static void Main(string[] args)
        {
            ThreadWorkItem wItem = null;
            Thread t = null;

            var threadNum = 2;


            for (int i = 0; i < threadNum; i++)
            {

                t = new Thread(o=>
                {
                    var w = o as ThreadWorkItem;
                    if (w == null) return;
                    while (true)
                    {
                        if (!w.Flag)
                        {
                            Console.WriteLine("我是线程:" + Thread.CurrentThread.Name);
                            Thread.Sleep(1000);
                            continue;
                        }
                        //避免CPU空转
                        Thread.Sleep(5000);

                    }

                });
                //$ C#6.0语法糖
                t.Name = $"Hello I'am 线程:{i}-{t.ManagedThreadId}";
                wItem = new ThreadWorkItem
                {
                    Flag = false,
                    Thread = t,
                    ThreadManagerId = t.ManagedThreadId,
                    ThreadName = t.Name
                };
                Works.Add(wItem);
                t.Start(Works[i]);
            }

            //5秒后允许一个等待的线程继续。当前允许的是线程1
            Thread.Sleep(5000);
            Works[0].Flag = true;
            Console.WriteLine($"thread-{Works[0].ThreadName} is 暂停");



            //5秒后允许一个等待的线程继续。当前允许的是线程0,1
            Thread.Sleep(5000);
            Works[0].Flag = false;
            Console.WriteLine($"thread-{Works[0].ThreadName} is 恢复");


        }
    }
View Code

方式2:使用ManualResetEvent控制挂起线程和恢复线程(推荐);替代Thread类中被微软标记过时的函数(内核模式非混合模式)

    public class Program
    {
        //线程工作集合
        static List<ThreadWorkItem> Works = new List<ThreadWorkItem>();

        //方式2:使用ManualResetEvent控制挂起线程和恢复线程(推荐);替代Thread类中被微软标记过时的函数
        static void Main(string[] args)
        {

            Task.Factory.StartNew(() =>
            {
                Thread t = null;
                ThreadWorkItem item = null;
                for (int i = 0; i < 2; i++)
                {
                    t = new Thread((o) =>
                    {
                        var w = o as ThreadWorkItem;
                        if (w == null) return;

                        while (true)
                        {
                            //阻塞当前线程
                            w.ManualResetEvent.WaitOne();

                            Console.WriteLine("我是线程:" + Thread.CurrentThread.Name);
                            Thread.Sleep(1000);
                        }

                    });
                    t.Name = "Hello,i 'am Thread: " + i;
                    item = new ThreadWorkItem
                    {
                        //线程0,1持续运行,设置true后非阻塞,持续运行。需要手动触发Reset()才会阻塞实例所在当前线程
                        ManualResetEvent = new ManualResetEvent(true),
                        Thread = t,
                        ThreadManagerId = t.ManagedThreadId,
                        ThreadName = t.Name
                    };
                    Works.Add(item);
                    t.Start(item);
                }



                //5秒后准备暂停一个线程1。线程0持续运行

                Thread.Sleep(5000);
                Console.WriteLine("close...");
                Works[1].ManualResetEvent.Reset();

                //5秒后恢复线程1;线程0,1持续运行
                Thread.Sleep(5000);
                Console.WriteLine("open...");
                Works[1].ManualResetEvent.Set();

                //5秒后准备暂停一个线程0。线程1持续运行
                Thread.Sleep(5000);
                Console.WriteLine("close0...");
                Works[0].ManualResetEvent.Reset();

                //5秒后恢复线程1;线程0,1持续运行
                Thread.Sleep(5000);
                Console.WriteLine("open0...");
                Works[0].ManualResetEvent.Set();

            });


            Console.ReadLine();
        }

    }
View Code

三、总结

 1.有时候会觉得必须由主线程创建ManualResetEvent实例才能起到作用,实际并不是这样的,上述方式2则证明了这一点。

 2.那么AutoResetEvent做不到同样的效果吗?

     答:AutoResetEvent 顾名思义,自动Reset()表示重置信号量状态,当前线程中持有WaitOne()就又会被持续阻塞。而ManualResetEvent必须要手动调用Reset()才能重置信号量,这里再解释下Set(),它表明允许一个或多个被同一个ManualResetEvent实例WaitOne()的线程放行。

 3.实例化信号量的构造参数是什么意思?

     答:信号量非终止状态,如果值为false则表明终止状态,调用WaitOne()方法的时候立即阻塞。设置true可以理解为隐式调用了Set()方法放行一次。

 4. ManualResetEvent和AutoResetEvent的区别

     答:ManualResetEvent调用Set()允许一个或多个被同一个ManualResetEvent实例WaitOne()的线程放行。

           AutoResetEvent调用Set() 只能允许一个线程放行。如果多处使用同一个实例,则需要手动调用多次Set()

原文地址:https://www.cnblogs.com/gaobing/p/5124945.html