如何優雅地控制線程狀態

爲了控制線程狀態,Thread類中提供了Suspend,Resume,Abort等方法。但Suspend和Resume方法已被MS標註爲已過時(Obsolete),若是簡單的爲線程設置一些狀態量,又會牽扯出跨線程訪問的問題,所以要尋求新的更優的解決方案。在論壇上上看到一篇文章,同時介紹了工作線程在線程池中時的控制方法,很不錯。代碼註釋很全面,一看便懂。

class Program
    {
        static void Main(string[] args)
        {
            UseThreadAPI();
            UseSyncEvent();
            UseThreadPool();
            UseSyncEventThreadPool();
            Console.WriteLine("All tests  finished");
            Console.ReadKey();
        }
        /// <summary>
        /// 使用標準Thread API來控制線程狀態,
        /// Suspend和Resume是過時的方法,MS不推薦使用
        /// MS推薦的方式就是後面要提到的使用Monitor,Event等做同步控制.
        /// </summary>
        static void UseThreadAPI()
        {
            Console.WriteLine("----------Use thread API----------");
            Thread t = new Thread(
                new ThreadStart(() =>
                {
                    while (true)
                    {
                        Console.WriteLine("Now Date:{0}", DateTime.Now);
                        Thread.Sleep(1000);
                    }
                }
                ));
            t.Start();
            //暫停線程執行
            Console.ReadKey();
            t.Suspend();
            Console.WriteLine("Thread suspended");
            //繼續線程執行
            Console.ReadKey();
            t.Resume();
            Console.WriteLine("Thread resumed");
            //結束線程
            Console.ReadKey();
            t.Abort();
            Console.WriteLine("Thread aborted");
            Console.ReadKey();
        }
        /// <summary>
        /// 使用Event做同步控制
        /// 三個Event組合使用就可以產生同Suspend,Resuem,Abort相同的效果
        /// 而且你可以控制Abort的時機以及並作出適當的處理
        /// 而不是像Thread.Abort一樣通過異常的方式結束線程
        /// </summary>
        static void UseSyncEvent()
        {
            Console.WriteLine("----------Use  sync event----------");
            AutoResetEvent evtPause = new AutoResetEvent(false);
            AutoResetEvent evtResume = new AutoResetEvent(false);
            AutoResetEvent evtStop = new AutoResetEvent(false);
            Thread t = new Thread(
                new ThreadStart(() =>
                {
                    //WaitOne(1000),可產生Sleep(1000)相同的效果
                    //如果eveStop被置位,則立即返回True,跳出循環
                    //如果等待1000ms超時,則返回False,繼續循環
                    while (!evtStop.WaitOne(1000))
                    {
                        //WaitOne(0)可立即判斷evtPase有沒有被置位
                        //如果置位,進入暫停狀態,等待Resume被置位纔會恢復線程執行
                        if (evtPause.WaitOne(0))
                        {
                            //WaitOne()不帶參數表示一直等待,直到被置位
                            evtResume.WaitOne();
                        }
                        Console.WriteLine("Now Date:{0}", DateTime.Now);
                    }
                }
                ));
            t.Start();
            //暫停線程執行
            Console.ReadKey();
            evtPause.Set();
            Console.WriteLine("Thread suspended");
            //繼續線程執行
            Console.ReadKey();
            evtResume.Set();
            Console.WriteLine("Thread resumed");
            //結束線程
            Console.ReadKey();
            evtStop.Set();
            Console.WriteLine("Thread stopped");
            Console.ReadKey();
        }
        class ThreadStatusController
        {
            /// <summary>
            /// 聲明爲volatile可以避免用lock進行加鎖同步
            /// 編譯器自己會做優化
            /// 另外不能聲明屬性爲volatile,因此只能作爲成員變量放出.
            /// </summary>
            public volatile bool IsPauseRequired;
            public volatile bool IsStopRequired;
        }
        /// <summary>
        /// 對於放入線程池的進程,是無法通過Thread的API進行控制的
        /// 通常的做法是通過一些bool量做控制,這不是優雅的解決方案.
        /// </summary>
        static void UseThreadPool()
        {
            Console.WriteLine("----------Use thread pool----------");
            var tsc = new ThreadStatusController();
            ThreadPool.QueueUserWorkItem(status =>
            {
                var ctrl = status as ThreadStatusController;
                //等待IsStopRequired標誌量的值爲True
                while (!ctrl.IsStopRequired)
                {
                    //如果不是Pause請求,則執行
                    if (!ctrl.IsPauseRequired)
                        Console.WriteLine("Now Date:{0}", DateTime.Now);
                    Thread.Sleep(1000);
                }
            
            }, tsc);
            //暫停線程執行
            Console.ReadKey();
            tsc.IsPauseRequired = true;
            Console.WriteLine("Thread suspended");
            //繼續線程執行
            Console.ReadKey();
            tsc.IsPauseRequired = false;
            Console.WriteLine("Thread resumed");
            //結束線程
            Console.ReadKey();
            tsc.IsStopRequired = true;
            Console.WriteLine("Thread aborted");
            Console.ReadKey();
        }
        /// <summary>
        /// 聲明三個同步事件分別對應三種同步狀態
        /// </summary>
        class ThreadStatusEventController
        {
            public ThreadStatusEventController()
            {
                PauseEvent = new AutoResetEvent(false);
                ResumeEvent = new AutoResetEvent(false);
                StopEvent = new AutoResetEvent(false);
            }
            public AutoResetEvent PauseEvent { get; set; }
            public AutoResetEvent ResumeEvent { get; set; }
            public AutoResetEvent StopEvent { get; set; }
        }
        static void UseSyncEventThreadPool()
        {
            Console.WriteLine("----------Use sync event with thread pool----------");
            var tsc = new ThreadStatusEventController();
            ThreadPool.QueueUserWorkItem(status =>
            {
                var ctrl = status as ThreadStatusEventController;
                //控制代碼跟採用Thread的方式類似,不累述
                while (!ctrl.StopEvent.WaitOne(1000))
                {
                    if (ctrl.PauseEvent.WaitOne(0))
                    {
                        ctrl.ResumeEvent.WaitOne();
                    }
                    Console.WriteLine("Now Date:{0}", DateTime.Now);
                }
            }, tsc);
            //暫停線程執行
            Console.ReadKey();
            tsc.PauseEvent.Set();
            Console.WriteLine("Thread suspended");
            //繼續線程執行
            Console.ReadKey();
            tsc.ResumeEvent.Set();
            Console.WriteLine("Thread resumed");
            //結束線程
            Console.ReadKey();
            tsc.StopEvent.Set();
            Console.WriteLine("Thread aborted");
            Console.ReadKey();
        }
    
    }

文章來源:http://www.cnblogs.com/bloodish/archive/2011/03/21/1990025.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章