C# Thread掛起線程和恢復線程

前言ide

衆所周知,Thread類中的掛起線程和恢復線程微軟已標記過期,由於可能會形成問題函數

  Resume()   恢復當前線程

已過期。 Resumes a thread that has been suspended.ui

  Suspend()   掛起當前線程

已過期。 掛起線程,或者若是線程已掛起,則不起做用。spa

其餘方式實現線程

1、ThreadWorkItemcode

  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; }

    }

 

2、C# Thread掛起線程和恢復線程的實現的兩種方式blog

 

方式1:使用變量開關控制掛起線程和恢復線程,具體代碼以下get

    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類中被微軟標記過期的函數(內核模式非混合模式)string

    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

 

3、總結it

 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()

相關文章
相關標籤/搜索