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
这两个阻塞事件类来实现。
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()常用于线程内部自阻塞
}
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内容
}
... //线程剩余内容
}
}
// 线程内部写法参考【详解】
// 其他线程中的部分:由于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();
···
线程Start之前调用Abort
线程会在Start被调用时终止线程。
线程Sleeping的时候调用Abort
线程被中断,然后终止线程
线程Blocked的时候调用Abort
线程被中断,然后终止线程
线程被挂起的时候调用Abort
Throw ThreadStartException 引发Abort的调用,然后AbortRequested 被加到正在被终止的线程的ThreadState属性
一个托管线程正在执行非托管代码时调用Abort
ThreadAbortException不会被抛出直到线程返回托管代码。
如果同时Abort两个线程,有可能一个线程会设置状态信息,而另外一个线程执行Abort的方法。然而,应用程序不会检测到这种情形。
注意Abort方法是通过抛出ThreadAbortException异常而强制结束线程,尽量少用。
多线程其实是调用一个方法栈,return可以结束方法,要说不好的地方就是
可能造成return污染,使其他方法受到影响。
public enum ThreadState
{
Running = 0x0,
StopRequested = 0x1,
SuspendRequested = 0x2,
Background = 0x4,//后台线程会随着主线程结束而(强制)结束,前台线程全部执行完主线程才能结束
Unstarted = 0x8,
Stopped = 0x10,
WaitSleepJoin = 0x20,
Suspended = 0x40,
AbortRequested = 0x80,
Aborted = 0x100
}