C# Tip -- 如何优雅的控制线程状态

本文探讨了为什么不应使用Thread的Suspend和Resume方法来控制线程状态,而应采用同步事件进行线程管理。通过示例展示了如何使用AutoResetEvent进行线程的挂起、继续和结束操作,以及如何应用于线程池中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

先问读者一个问题,如果想控制一个线程(Thread)挂起,继续,结束你会优先选择如何处理?

从面试的经验来看,多数的面试者都会说Thread不是提供了Suspend,Resume,Abort等方法吗,直接调用就好了,简单快捷.但很多情况下简单就是美只是一个谎言而已.

Suspend和Resume方法已经被MS标注过时(Obsolete),不建议用户使用,MS同时推荐通过同步控制来管理线程状态.

再问读者一个问题,如果控制一个线程池中的线程的挂起,继续,结束你会优先选择如何处理?

也许有人会说,既然没法用API了,那我定义一些标志量,来做状态控制不就可以了吗?

确实,说起来很简单.那么变量的值需不需要考虑由于多线程问题导致的读写问题呢,你会怎么处理?

如果不用标志量,可以用同步事件来做,会不会更优雅一些呢?

让我把传统的方式以及使用同步方式做的控制都写一遍,让读者来做取舍吧.

代码如下,注释也比较全,就不再累述细节.

 


 

 

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

        }

 

    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值