赞
踩
本文转载自:https://blog.csdn.net/weixin_44295783/article/details/117464768
Thread.Sleep(int millisecondsTimeout)还有一个重载Thread.Sleep(TimeSpan timeout),作用是将当前线程挂起一定的时长,期间放弃CPU使用权,时间到了自动恢复线程和其他线程一起参与CPU的竞争。
- //调用——Thread类的静态方法
- Thread.Sleep(1000);//将当前所在进程挂起1000ms
-
- Timespan ts=new Timespan(1,20,33);//创建一个时间间隔对象,长度为1h22min33s
- Thread.Sleep(ts);//将当前线程挂起1h22min33s
Thread.SpinWait(int iterations)也是Thread类的静态方法,将当前线程等待一定长的时间(ms为单位),期间占用时间片,不放弃CPU的使用权,类似于让CPU执行一段无效代码。
- //调用
- Thread.SpinWait(1000);//将当前线程等待1000ms,等待结束后可以立即执行不需要重新参与CPU竞争
Interrupt方法只可以中断处于 WaitSleepJoin 状态的线程,抛出异常并改变该线程的状态,线程将恢复执行。
如果一个线程处于阻塞状态(如调用了Sleep()、Join()等阻塞方法以及可中断通道的I/O操作后的阻塞),则在线程状态为WaitSleepJoin状态时,就会在阻塞方法调用处抛出ThreadInterruptException异常,并且在抛出异常后将线程状态设置为其他状态,从而线程从阻塞状态醒过来,并在结束线程前让程序员有足够的时间来处理中断请求。
- //调用
- thread.Interupt();
thread.Join()表示thread线程终止之前阻止调用其他线程,thread终止之后自动恢复原来的线程,通常在其他线程或者主线程中使用此方法,起到临时强制优先执行特定线程的效果。
- //调用
- thread.Join();//可以有参数,表示合并的时长
C#已经弃用了不安全的Suspend()和Resume(),现在实现线程的暂停与灰度可以通过AutoResetEvent和ManualResetEvent这两个阻塞事件类来实现。
AutoResetEvent
- public class
- {
- //实例化AutoResetEvent对象,参数bool表示are初始的状态,true表示通过
- private static AutoResetEvent are = new AutoResetEvent(true);
- Thread th=new Thread(new ThreadStart(ThTest));
- private static ThTest()
- {
- are.WaitOne();
- Console.WriteLine(1);
- are.WaitOne();
- Console.WriteLine(2);
- are.WaitOne();
- Console.WriteLine(3);
- }
-
- 主函数()
- {
- th.Start();
- Console.ReadLine();
- are.Set();
- }
-
- //输出
- 1
- 2
-
- //解析
- //遇到第一个are.WaitOne()时,由于阻塞事件对象are的初始状态为可通过(true),所以th直接通过,同时are的状态改为不可通过,接着输出1
- //遇到第二个are.WaitOne()时,由于are的状态为不可通过,所以th被are阻塞,等待其他线程发送信号。
- //主线程上are.Set()发送了are处可通过的信号,th通过第二个are.WaitOne(),同时are的状态改为不可通过,输出2
- //遇到第三个are.WaitOne(),th又被阻塞,它只能等待,直到主线程结束也没有通过,th被强行终止
- //AutoResetResult中的Reset()常用于线程内部自阻塞
- }
ManualResetEvent
- public class
- {
- //实例化ManualResetEvent对象,参数bool表示mre初始的状态,false表示不通过
- private static ManualResetEvent mre = new ManualResetEvent(false);
- Thread th=new Thread(new ThreadStart(ThTest));
- private static ThTest()
- {
- mre.WaitOne();
- Console.WriteLine(1);
- mre.WaitOne();
- Console.WriteLine(2);
- mre.Reset();
- mre.WaitOne();
- Console.WriteLine(3);
- mre.WaitOne();
- Console.WriteLine(4);
- }
-
- 主函数()
- {
- th.Start();
- Console.ReadLine();
- mre.Set();
- }
-
- //输出
- 1
- 2
-
- //解析
- //遇到第一个mre.WaitOne()时,由于阻塞事件对象mre的初始状态为不可通过(false),所以th阻塞
- //这时主线程发送mre.Set()使mre变为通过状态,th通过第一个mre.WaitOne(),输出1
- //紧接着遇到第二个mre.WaitOne(),mre状态还是通过,th通过第二个mre.WaitOne(),输出2
- //这时线程内部将mre状态置为不可通过
- //遇到第三个mre.WaitOne()时,th被阻塞,mre状态为不可通过,th一直等待
- //直到主线程结束也没有通过,th被强行终止
- }
线程一旦中止就无法再重启。
- static void Main(string[] args)
- {
- CancellationTokenSource cts = new CancellationTokenSource();
- Thread t = new Thread(() =>
- {
- while(true)
- {
- if(cts.Token.IsCancellationRequested)
- {
- Console.WriteLine("Cancled信号触发!");
- Console.WriteLine(Thread.CurrentThread.ThreadState.ToString());
- break;
- }
- Console.WriteLine(DateTime.Now.ToString());
- Thread.Sleep(1000);
- }
- Console.WriteLine("线程终止!");
- });
- t.Start();
- Console.ReadLine();
- cts.Cancel();
- Console.WriteLine("main:线程已停止!");
- Console.WriteLine(t.ThreadState.ToString());
- Console.ReadKey();
- Thread.Sleep(2000);
- Console.WriteLine(t.ThreadState.ToString());
- Console.ReadKey();
- }
-
- //输出
- 2021/6/2 11:38:47
- 2021/6/2 11:38:48
- 2021/6/2 11:38:49
- 2021/6/2 11:38:50
- 2021/6/2 11:38:51
-
- main:线程已停止!
- WaitSleepJoin
- Cancled信号触发!
- Running
- 线程终止!
- Stopped
-
Abort()终止当前线程时在当前线程上引发ThreadAbortException 异常,且只对托管代码有用。ThreadAbortExcetion是一个可以被应用程序捕获的特殊异常,在catch 块中会自动重新抛出这个异常,除非在catch块中调用ResetAbort方法。Thread.ResetAbort()可以取消掉终止的请求,而且可以防止catch中再次抛出的ThreadAbortException终止当前线程。未执行的Finally块会在线程终止前执行。
tips:1·托管代码指的是由CLR负责管理执行(托管)的代码,往往以IL(中间语言)的形式被CLR执行;2·非托管代码指的是由操作系统直接负责在机器上执行的代码,不享受CLR提供的内存管理等服务,通常为MFC、WIN32、ALT等项目。
详解
- public class ThreadWork
- {
- public static void DoWork()
- {
- try
- {
- ... //try的内容
- }
- catch (ThreadAbortException e)
- {
- ... //catch的内容
-
- //Thread.ResetAbort();
-
- ... //catch的内容
- }
- finally
- {
- ... //finally内容
- }
-
- ... //线程剩余内容
- }
- }
1.取消终止线程的请求,并恢复线程,继续执行ResetAbort后面的语句,然后执行catch块之 后的语句
2.若Catch块之后有Finally块,则执行Finally块,然后执行Finally块后面的语句。
1.finally块在线程终止前执行,finally块之后的语句不会被执行,然后线程终止。
catch和finally中的代码一定会被执行
用法
- // 线程内部写法参考【详解】
-
- // 其他线程中的部分:由于Abort()后还要执行一部分代码,所以线程不会即刻停止。为防止catch和finally中的代码耗时过长而影响其他线程,我们需要做一定的操作来等待线程的完成或终止。
- //1. 循环等待
- th.Abort();
- while(th.ThreadState!=ThreadState.Aborted)
- {
- //当调用Abort方法后,如果thread线程的状态不为Aborted,主线程就一直在这里做循环,直到thread线程的状态变为Aborted为止
- Thread.Sleep(100);
- }
- //当跳出上面的循环后就表示我们启动的线程thread已经完全终止了
- ···
-
-
- //2. Join等待
- th.Abort();
- th.Join();
- ···
Abort调用的时间
1.线程Start之前调用Abort
线程会在Start被调用时终止线程。
2.线程Sleeping的时候调用Abort
线程被中断,然后终止线程
3.线程Blocked的时候调用Abort
线程被中断,然后终止线程
4.线程被挂起的时候调用Abort
Throw ThreadStartException 引发Abort的调用,然后AbortRequested 被加到正在被终止的线程的ThreadState属性
5.一个托管线程正在执行非托管代码时调用Abort
ThreadAbortException不会被抛出直到线程返回托管代码。
6.如果同时Abort两个线程,有可能一个线程会设置状态信息,而另外一个线程执行Abort的方法。然而,应用程序不会检测到这种情形。
注意Abort方法是通过抛出ThreadAbortException异常而强制结束线程,尽量少用。
多线程其实是调用一个方法栈,return可以结束方法,要说不好的地方就是
可能造成return污染,使其他方法受到影响。
个人理解原理就是传递一个全局变量来通知线程,没必要使用它给的那个类,可能有其他的用处。个人更喜欢Abort()和return,停止请求发出后需要进行一份操作就用Abort(),因为可以捕捉异常;只需要立刻停掉就return。
附:ThreadState状态表
- public enum ThreadState
- {
- Running = 0x0,
- StopRequested = 0x1,
- SuspendRequested = 0x2,
- Background = 0x4,//后台线程会随着主线程结束而(强制)结束,前台线程全部执行完主线程才能结束
- Unstarted = 0x8,
- Stopped = 0x10,
- WaitSleepJoin = 0x20,
- Suspended = 0x40,
- AbortRequested = 0x80,
- Aborted = 0x100
- }
原文链接:https://blog.csdn.net/weixin_44295783/article/details/117464768
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。