- 什么是线程阻塞
(1)如果线程因为某种原因导致暂停,那么就认为该线程被阻塞了
例如:使用Thread.Sleep()或者Join方法
(2)被阻塞的线程会立即将其处理器的时间片生成给其他线程,从此就不在消耗处理器时间,知道满足阻塞条件后,处理器重新为线程分配时间片
可以通过ThreadState这个属性来判断线程是否处于被阻塞状态
bool block =(Thread.ThreadState&ThreadState.WaitSeelpJoin)!=0//如果为true则为阻塞状态
ThreadState是一个flags enum,通过按位的形式,可以合并数据的选项
-
解除阻塞Unblocking
(1)当阻塞的条件被满足时
(2)操作超时(如果设置超时的话)
(3)通过Thread.Interrupt()进行打断
(4)通过Thread.Abort()进行终止 -
上下文切换
当线程阻塞或解除阻塞时,操作系统将执行上下文切换.这会产生少量的开销,通常为1微秒 -
I/Obound 和 Compute-bound (又叫CPU-bound)
(1)一个花费大部分时间等待某件事发生的操作成为I/O-bound (2)I/O-bunod通常涉及输入和输出,但这不是硬性要求:Thread.Sleep()也被视为I/O-bound (3)一个花费大量时间执行CPU密集型工作的操作被称为Compute-bound
-
阻塞(Blocking)和忙等待(自旋)(Spinning)
IO-bound的操作方式有两种: 在线程上同步的等待 例如:Console.ReadLine(),Thread.Sleep(),Thread.Join() 异步的操作,在稍后完成时触发一个回调动作
同步等待的I/O-bound将大部分时间花在阻塞线程上
它们也可以周期性的在一个循环里进行打转
While(DateTime.Now<nexDateTime)
{ Thread.Sleep(100) } //忙等待跟I/O-Bound结合
While(DateTime.Now<nexDateTime);//纯粹的忙等待
区别:
(1)如果希望条件很快得到满足(可能在几微秒之内),则短暂的自旋可能会很有效,因为它避免了上下文切换的开销和切换
NET Framework提供了特殊的方法和类来提供帮助SpinLock和SpinWait
(2)其次阻塞也不是零成本的.这是因为每个线程在生存期间会占用大约1MB的内存,并会给CLR和操 作系统带来持续的管理和开销
(3)因此,在需要处理成百上千并发操作的大量I/O-bound程序的上下文中,阻塞可能会很麻烦所以此程序需要使用基于回调方法,在等待时完全撤销其线程。
var state = ThreadState.Unstarted | ThreadState.WaitSleepJoin | ThreadState.Running;
Console.WriteLine("{0}", Convert.ToString((int)state, 2));//获取当前线程的状态并转为二进制
6 ThreadState剥离
但是它大部分的枚举值都没有什么用,可以将ThreadState剥离为四个值:Unstarted,Running,WaitSleepJoin,Stopped
public static ThreadState SimpeThreadState(ThreadState ts)
{
return ts & (ThreadState.Unstarted |
ThreadState.Running |
ThreadState.WaitSleepJoin |
ThreadState.Stopped);
}
ThreadState属性可用于诊断的目的,但不适用于同步,因为线程状态可能会在测试ThreadState和对该信息进行操作直接发生变化