• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

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

原作者: [db:作者] 来自: [db:来源] 收藏 邀请
先问读者一个问题,如果想控制一个线程(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();
}

}
 

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
在C#中读写INI配置文件发布时间:2022-07-10
下一篇:
C#Path有关于文件路径获取的问题的方法发布时间:2022-07-10
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap