当前位置:   article > 正文

C#多线程——Thread睡眠、中断、合并、暂停与恢复、终止_c# thread.sleep

c# thread.sleep

本文转载自:https://blog.csdn.net/weixin_44295783/article/details/117464768

一、睡眠

Sleep(int millisecondsTimeout)

Thread.Sleep(int millisecondsTimeout)还有一个重载Thread.Sleep(TimeSpan timeout),作用是将当前线程挂起一定的时长,期间放弃CPU使用权,时间到了自动恢复线程和其他线程一起参与CPU的竞争。

  1.  //调用——Thread类的静态方法
  2.  Thread.Sleep(1000);//将当前所在进程挂起1000ms
  3.  
  4.  Timespan ts=new Timespan(1,20,33);//创建一个时间间隔对象,长度为1h22min33s
  5.  Thread.Sleep(ts);//将当前线程挂起1h22min33s

SpinWait(int iterations)

Thread.SpinWait(int iterations)也是Thread类的静态方法,将当前线程等待一定长的时间(ms为单位),期间占用时间片,不放弃CPU的使用权,类似于让CPU执行一段无效代码。

  1. //调用
  2. Thread.SpinWait(1000);//将当前线程等待1000ms,等待结束后可以立即执行不需要重新参与CPU竞争

二、中断Interrupt

Interrupt方法只可以中断处于 WaitSleepJoin 状态的线程,抛出异常并改变该线程的状态,线程将恢复执行。
如果一个线程处于阻塞状态(如调用了Sleep()、Join()等阻塞方法以及可中断通道的I/O操作后的阻塞),则在线程状态为WaitSleepJoin状态时,就会在阻塞方法调用处抛出ThreadInterruptException异常,并且在抛出异常后将线程状态设置为其他状态,从而线程从阻塞状态醒过来,并在结束线程前让程序员有足够的时间来处理中断请求。

  1. //调用
  2. thread.Interupt();

三、合并Join

thread.Join()表示thread线程终止之前阻止调用其他线程,thread终止之后自动恢复原来的线程,通常在其他线程或者主线程中使用此方法,起到临时强制优先执行特定线程的效果。

  1. //调用
  2. thread.Join();//可以有参数,表示合并的时长

四、暂停与恢复

C#已经弃用了不安全的Suspend()和Resume(),现在实现线程的暂停与灰度可以通过AutoResetEventManualResetEvent这两个阻塞事件类来实现。

两种事件的不同

  • AutoResetEvent是自动阻塞,同时只允许一个线程通过一次,然后继续阻塞,类似于小区门口测体温
  • ManualResetEvent是手动阻塞,打开后需要手动阻塞,否则会一直打开;阻塞后需要手动打开,否则会一直阻塞,类似于水龙头

Set()、Reset()与WaitOne()

  • WaitOne()阻塞线程,等待信号;有带参数的重载,设置等待时间以及等待超时的操作
  • Set()方法可以发出可通过信号
  • Reset()方法可以发出不可通过信号

使用

AutoResetEvent

  1. public class
  2. {
  3. //实例化AutoResetEvent对象,参数bool表示are初始的状态,true表示通过
  4. private static AutoResetEvent are = new AutoResetEvent(true);
  5. Thread th=new Thread(new ThreadStart(ThTest));
  6. private static ThTest()
  7. {
  8. are.WaitOne();
  9. Console.WriteLine(1);
  10. are.WaitOne();
  11. Console.WriteLine(2);
  12. are.WaitOne();
  13. Console.WriteLine(3);
  14. }
  15. 主函数()
  16. {
  17. th.Start();
  18. Console.ReadLine();
  19. are.Set();
  20. }
  21. //输出
  22. 1
  23. 2
  24. //解析
  25. //遇到第一个are.WaitOne()时,由于阻塞事件对象are的初始状态为可通过(true),所以th直接通过,同时are的状态改为不可通过,接着输出1
  26. //遇到第二个are.WaitOne()时,由于are的状态为不可通过,所以th被are阻塞,等待其他线程发送信号。
  27. //主线程上are.Set()发送了are处可通过的信号,th通过第二个are.WaitOne(),同时are的状态改为不可通过,输出2
  28. //遇到第三个are.WaitOne(),th又被阻塞,它只能等待,直到主线程结束也没有通过,th被强行终止
  29. //AutoResetResult中的Reset()常用于线程内部自阻塞
  30. }

ManualResetEvent

  1. public class
  2. {
  3. //实例化ManualResetEvent对象,参数bool表示mre初始的状态,false表示不通过
  4. private static ManualResetEvent mre = new ManualResetEvent(false);
  5. Thread th=new Thread(new ThreadStart(ThTest));
  6. private static ThTest()
  7. {
  8. mre.WaitOne();
  9. Console.WriteLine(1);
  10. mre.WaitOne();
  11. Console.WriteLine(2);
  12. mre.Reset();
  13. mre.WaitOne();
  14. Console.WriteLine(3);
  15. mre.WaitOne();
  16. Console.WriteLine(4);
  17. }
  18. 主函数()
  19. {
  20. th.Start();
  21. Console.ReadLine();
  22. mre.Set();
  23. }
  24. //输出
  25. 1
  26. 2
  27. //解析
  28. //遇到第一个mre.WaitOne()时,由于阻塞事件对象mre的初始状态为不可通过(false),所以th阻塞
  29. //这时主线程发送mre.Set()使mre变为通过状态,th通过第一个mre.WaitOne(),输出1
  30. //紧接着遇到第二个mre.WaitOne(),mre状态还是通过,th通过第二个mre.WaitOne(),输出2
  31. //这时线程内部将mre状态置为不可通过
  32. //遇到第三个mre.WaitOne()时,th被阻塞,mre状态为不可通过,th一直等待
  33. //直到主线程结束也没有通过,th被强行终止
  34. }

五、线程中止

线程一旦中止就无法再重启。

  • 协作式取消(Cooperative Cancellation)
  • Abort()
  • return

协作式取消(Cooperative Cancellation)——正确停止线程

  • 类似于AutoResetEvent和ManualResetEvent,通过在线程自身内部开放给调用者接口(传递信号量),并在工作时检测对应的标识:Cancled ,实现响应调用者的请求。
  • 与Abort()不同的是:不在于用户采取了什么行为,而在于线程是否能主动响应停止请求。
  • 机制:线程在工作时以某种频率检测Cancled标识,若检测到Cancled,则线程自己负责退出。
  1. static void Main(string[] args)
  2. {
  3. CancellationTokenSource cts = new CancellationTokenSource();
  4. Thread t = new Thread(() =>
  5. {
  6. while(true)
  7. {
  8. if(cts.Token.IsCancellationRequested)
  9. {
  10. Console.WriteLine("Cancled信号触发!");
  11. Console.WriteLine(Thread.CurrentThread.ThreadState.ToString());
  12. break;
  13. }
  14. Console.WriteLine(DateTime.Now.ToString());
  15. Thread.Sleep(1000);
  16. }
  17. Console.WriteLine("线程终止!");
  18. });
  19. t.Start();
  20. Console.ReadLine();
  21. cts.Cancel();
  22. Console.WriteLine("main:线程已停止!");
  23. Console.WriteLine(t.ThreadState.ToString());
  24. Console.ReadKey();
  25. Thread.Sleep(2000);
  26. Console.WriteLine(t.ThreadState.ToString());
  27. Console.ReadKey();
  28. }
  29. //输出
  30. 2021/6/2 11:38:47
  31. 2021/6/2 11:38:48
  32. 2021/6/2 11:38:49
  33. 2021/6/2 11:38:50
  34. 2021/6/2 11:38:51
  35. main:线程已停止!
  36. WaitSleepJoin
  37. Cancled信号触发!
  38. Running
  39. 线程终止!
  40. Stopped

Abort() 立即终止一个线程

Abort()终止当前线程时在当前线程上引发ThreadAbortException 异常,且只对托管代码有用。ThreadAbortExcetion是一个可以被应用程序捕获的特殊异常,在catch 块中会自动重新抛出这个异常,除非在catch块中调用ResetAbort方法。Thread.ResetAbort()可以取消掉终止的请求,而且可以防止catch中再次抛出的ThreadAbortException终止当前线程。未执行的Finally块会在线程终止前执行。

tips:1·托管代码指的是由CLR负责管理执行(托管)的代码,往往以IL(中间语言)的形式被CLR执行;2·非托管代码指的是由操作系统直接负责在机器上执行的代码,不享受CLR提供的内存管理等服务,通常为MFC、WIN32、ALT等项目。

详解

  1. public class ThreadWork
  2. {
  3. public static void DoWork()
  4. {
  5. try
  6. {
  7. ... //try的内容
  8. }
  9. catch (ThreadAbortException e)
  10. {
  11. ... //catch的内容
  12. //Thread.ResetAbort();
  13. ... //catch的内容
  14. }
  15. finally
  16. {
  17. ... //finally内容
  18. }
  19. ... //线程剩余内容
  20. }
  21. }
  • 如果在catch中调用Thread.ResetAbort()

    1.取消终止线程的请求,并恢复线程,继续执行ResetAbort后面的语句,然后执行catch块之   后的语句
    2.若Catch块之后有Finally块,则执行Finally块,然后执行Finally块后面的语句。

  • 如果没有调用Thread.ResetAbort()

   1.finally块在线程终止前执行,finally块之后的语句不会被执行,然后线程终止。
catch和finally中的代码一定会被执行

用法

  1. // 线程内部写法参考【详解】
  2. // 其他线程中的部分:由于Abort()后还要执行一部分代码,所以线程不会即刻停止。为防止catch和finally中的代码耗时过长而影响其他线程,我们需要做一定的操作来等待线程的完成或终止。
  3. //1. 循环等待
  4. th.Abort();
  5. while(th.ThreadState!=ThreadState.Aborted)
  6. {
  7. //当调用Abort方法后,如果thread线程的状态不为Aborted,主线程就一直在这里做循环,直到thread线程的状态变为Aborted为止
  8. Thread.Sleep(100);
  9. }
  10. //当跳出上面的循环后就表示我们启动的线程thread已经完全终止了
  11. ···
  12. //2. Join等待
  13. th.Abort();
  14. th.Join();
  15. ···

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可以结束方法,要说不好的地方就是
可能造成return污染,使其他方法受到影响。

协作式停止线程是官方推荐写法

个人理解原理就是传递一个全局变量来通知线程,没必要使用它给的那个类,可能有其他的用处。个人更喜欢Abort()和return,停止请求发出后需要进行一份操作就用Abort(),因为可以捕捉异常;只需要立刻停掉就return。
附:ThreadState状态表

  1. public enum ThreadState
  2. {
  3. Running = 0x0,
  4. StopRequested = 0x1,
  5. SuspendRequested = 0x2,
  6. Background = 0x4,//后台线程会随着主线程结束而(强制)结束,前台线程全部执行完主线程才能结束
  7. Unstarted = 0x8,
  8. Stopped = 0x10,
  9. WaitSleepJoin = 0x20,
  10. Suspended = 0x40,
  11. AbortRequested = 0x80,
  12. Aborted = 0x100
  13. }


                        
原文链接:https://blog.csdn.net/weixin_44295783/article/details/117464768

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/1004267
推荐阅读
相关标签
  

闽ICP备14008679号