MultiThreading programming #1
MultiThreading programming #1
Thread
What is Thread ?
- 线程是一个可执行路径,每一个线程可以独立于其他线程执行
- 每个线程在均进程(Process)内执行,在操作系统中,进行提供了程序运行的独立环境
- 单线程应用,在进程的独立环境中只跑一个线程,该线程具有独占权
- 多线程应用,单个进程中跑多个线程,多个线程共享当前的执行环境(尤其是内存)
- 共享:多个线程共同占有某种资源,如一个线程在后台读取数据,另一个线程在数据到达后进行展示。
下面是c#中最简单的异步编程实例:
1 |
|
- 在单核计算机上,操作系统必须为每个线程分配时间片(Windows下通常为20ms)来模拟并发,从而在本例中,会输出重复的x块与y块
- 在多核或多处理器的计算机上,使用c#创建的多线程可以真正意义上并行执行。然而,在本例中由于控制台程序处理并发请求机制的微妙性,仍然会得到重复的x块与y块
- c#中线程的一些属性:
- 线程一旦开始执行,属性
IsAlive
就变为true
,线程结束就变为false
- 线程结束的条件:线程构造器中传入的委托结束了执行
- 线程一旦结束,便无法重启
- 每个线程都有一个
Name
属性,通常用于调试,Name
只能设置一次,多次更改会抛出异常 - 静态属性
Thread.CurrentThread
,指向当前执行的线程
- 线程一旦开始执行,属性
Join and Sleep
- 在线程A中调用另一个线程B实例的
Join
方法,线程A便会等待线程B执行结束后继续执行。 - 调用
Jion
方法时,可在参数中设置一个超时(毫秒/TimeSpan
)- 使用有超时的重载方法时返回值
bool
类型,true
:线程结束;false
:超时
- 使用有超时的重载方法时返回值
Thread.Sleep
方法会暂停当前的线程,并等待一段时间Thread.Sleep(0)
会导致县城立即放弃本身当前时间片,自动将cpu转交给其他线程Thread.Yield
与Thread.Sleep
做同样的事情,不同的是Thread.Yield
只会把执行交给同一处理器的其他线程- 当等待
Sleep
和Join
时,线程处于阻塞状态
1 |
|
在一次执行中,输出结果如下:
在此次运行过程中,线程t2
首先进入ThreadProc
,之后开始Sleep,时间片交给线程t1
,if判断成立,t1
进入阻塞状态等待t2
运行结束。t2
Sleep结束后开始运行,运行结束后,t1
继续运行直到结束
Blocking
- 如果线程的执行由于某种原因导致暂停,那么就认为该线程被阻塞了
- 如
Sleep
、Join
- 如
- 被阻塞的线程会立即将其时间片交给其他线程,从此不再消耗处理器时间,知道满足阻塞结束条件为止
- 可以通过
ThreadState
属性来判断线程是否处于阻塞状态 ThreadState
是一个flags enum,通过按位与/或来合并数据项ThreadState
变化图如下:
常用的状态只有四个:Unstarted
、Running
、WaitSleepJoin
和Stopped
1 |
|
当遇到下列四种情况解除阻塞:
- 阻塞条件被满足
- 操作超时(如果设置了超时)
- 通过
Thread.Interrupt()
进行打断 - 通过
Thread.Abort()
进行中止
上下文切换
- 当线程阻塞或解除阻塞时,操作系统执行上下文切换。这会产生少量开销,通常为1或2微秒
I/O密集型与CPU密集型
- 花费大部分时间等待某事发生的操作称为I/O密集型,通常此事指输入/输出,但不是硬性要求,如
Thread.Sleep()
被视为I/O密集型 - 相反,一个花费大部分时间执行CPU密集型的操作成为CPU密集型
- 花费大部分时间等待某事发生的操作称为I/O密集型,通常此事指输入/输出,但不是硬性要求,如
阻塞与忙等待
- 阻塞是在当前线程上同步的等待,
Console.ReadLine()
、Thread.Sleep()
、Thread.Join()
都是阻塞操作 - 忙等待以周期性的在一个循环里打转,也是同步的
while(DataTime.Now<nextStartTime)
- 还有一种异步的操作,在操作完成后触发回调
- 如果条件很快得到满足(在几微秒之内),短暂的忙等待更为适合,因为他避免了上下文切换的开销
- 阻塞是在当前线程上同步的等待,
Comment