type
status
date
slug
summary
tags
category
icon
password
Property
Aug 9, 2024 11:58 AM
阻塞
如果线程的执行由于某种原因导致暂停,那么就认为该线程被阻塞了
例如在Sleep或者通过Join等待其他线程结束
被阻塞的线程会立即将其处理器的时间片生成给其他线程,从此就不再小号处理器时间,直到满足其阻塞条件为止。
直到满足其阻塞条件为止:直到满足这个阻塞条件,处理器的时间片就回到本线程了,然后就可以继续消耗处理器的时间。
可以通过ThreadState这个恶属性来判断线程是否出于被阻塞的状态:
ThreadState
ThreadState是一个flags enum,通过按位的形式,可以合并数据的选项
运行状态的变化图
但是大部分的枚举值都没什么用,下面的代码将ThreadState剥离为四个最有用的值之一:Unstarted,Running,WaitSleepJoin,Stopped
ThreadState属性可用于诊断的目的,但不适用于同步,因为线程状态可能会在测试ThreadState和对该信息进行操作之间发生变化。
接触阻塞 Unblocking
当遇到下列四种情况的时候,就会解除阻塞
- 阻塞条件被满足
- 操作超时(如果设置超时的话)
- 通过Thread.Interrupt()进行打断
- 通过Thread.Abort()进行中止
上下文切换
当线程阻塞或解除阻塞时,操作系统将执行上下文切换。这回产生少量开销,通常为1~2微秒。
I/O-bound vs Computed-bound (或CPU-Bound)
一个花费大部分时间等待某事发生的操作称为I/O-bound
I/O绑定操作通常设计输入或输出,但这不是硬性要求:Thread.Sleep()也被视为I/O-bound。(干等着)
相反,一个花费大部分时间执行CPU密集型工作的操作称为Computed-bound
阻塞vs忙等待(自旋)Blocking vs Spinning
I/O-bound操作的工作方式有两种
在当前线程上的同步的等待
Consoe.Readline() Thread.Sleep() Thread.Join()
异步的操作,在稍后操作完成时触发一个回调动作。
同步等待的I/O-bound操作将大部分时间花在阻塞线程上
他们也可以周期性的在一个循环里进行“打转(自旋)”
在忙等待和阻塞放慢有一些细微差别
首先,如果您希望条件很快得到满足(可能在几微秒之内),短暂自旋可能会 很有效,因为它避免了上下文切换的开销和延迟
.NET Framework提供了特殊的方法和类来提供帮助SpinLock和SpinWait
其次,阻塞也不是零成本。这是因为每个线程在生存期间会占用大约1MB的内存,并会给CLR和操作系统带来持续的管理开销
因此,在需要处理成百上千个并发操作的大量I/O-bound程序的上下文中,阻塞可能会很麻烦
所以。此类程序需要使用基于回调的方法,在等待时完全撤销其线程
- 作者:Kitety
- 链接:https://www.kitety.com/article/c-sharp-async-thread-blocking
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章