zoukankan      html  css  js  c++  java
  • 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()

  • 相关阅读:
    内置函数拾遗
    jQuery与其他JS库冲突解决
    ckeditor+ckfinder添加水印。
    PostgreSQL与mysql的比较
    php函数 之 iconv 不是php的默认函数,也是默认安装的模块。需要安装才能用的。
    php mb_substr()函数的详细解释!
    成为一名PHP专家其实并不难
    php中级程序员的进化标准
    鼠标经过图片切换效果。
    计算两个日期之间的工作日
  • 原文地址:https://www.cnblogs.com/gaobing/p/5124945.html
Copyright © 2011-2022 走看看