C# 异步编程01

2023-11-30 19:12:33 浏览数 (1)

线程

概念:

  1. 线程是-一个可执行路径,它可以独立于其它线程执行。
  2. 每个线程都在操作系统的进程(Process) 内执行,而操作系统进程提供了程序运行的独立环境。
  3. 单线程应用,在进程的独立环境里只跑一个线程,所以该线程拥有独占权。
  4. 多线程应用,单个进程中会跑多个线程,它们会共享当前的执行环境(尤其是内存)
  • 例如一个线程在后台读取数据,另一个线程在数据到达后进行展示。
  • 这个数据就被称作是共享的状态。

线程抢占:

当线程在执行于另一个线程上代码的执行交织的那一点时,就可以称之为线程抢占。

线程常用属性:

  1. 线程-旦开始执行,IsAlive 就是true,线程结束就变成false。
  2. 线程结束的条件就是:线程构造函数传入的委托结束了执行。
  3. 线程一旦结束,就无法再重启。
  4. 每个线程都有个Name属性,通常用于调试。
  • 线程Name只能设置-次,以后更改会抛出异常。
  1. 静态的Thread.CurrentThread属性,会返回当先执行的线程

Thread.Join() 和 Thread.Sleep()

  • join() 方法可以等待另一个线程执行结束才继续往下执行。可以传入一个以毫秒为单位的数值,或者TimeSpan 都可以。
  • 如果join() 方法返回true,则表示线程结束了;如果超时了,就返回false。
  • Thread.Sleep() 方法会暂停当前的线程,并且等待一段时间。

注意:

  • Thread.Sleep(0) 这样的调用会导致线程立即放弃本身当前的时间片,自动将CPU移交给其他线程。
  • Thread.Yield() 做同样的事情,但是它只会把执行交给同意处理器上的其他线程。
  • 当等待Sleep 或 Join 的时候,线程处于阻塞的状态。

阻塞

  • 当线程的执行由于某种原因导致暂停,那么就认为该线程被阻塞了。例如在Sleep() 或者 通过Join() 等待其他线程结束。
  • 被阻塞的线程会立即将其处理器的时间片生成给其他线程,从此就不再消耗处理其时间,直至满足阻塞条件时。
  • 可以通过ThreadState 这个属性来判断线程是否处于被阻塞的状态。

ThreadState 线程状态

ThreadState 是一个flags enum,通过按位的形式,可以合并数据的选项。

但它大部分的枚举值都没什么用,一般而言,最常用的是四个值,Unstarted,Running,WaitSleepJoin 和 Stopped。

代码语言:javascript复制
bool blocked = (someThread. ThreadState & ThreadState .WaitSleepJoin) != 0;

可以通过以上的代码来判断线程是否是运行状态。

解除阻塞

当遇到下列四种情况的时候,就会解除阻塞。

  • 阻塞条件被满足
  • 操作超时(如果设置超时的话)
  • 通过Thread.Interrupt()进行打断
  • 通过Thread.Abort()进行中止
上下文切换

当线程阻塞或解除阻塞时,操作系统将执行上下文切换。这会产生少量开销,通常为1或2微秒。

阻塞 和 忙等待

线程各个状态示意图:

补充:

I/O 密集 和 计算密集

数据状态——本地和共享

对于共享状态的数据,保持线程安全则是非常重要的,因此

线程安全

为了维持线程安全,我们需要使用锁

在保证了线程安全的情况下,我们需要向线程传递数据

线程传递数据

补充一点在C#3.0之前

需要注意的是,使用lambda表达式时,需要注意变量的存放。

异常处理

一般情况下,如果需要捕获子线程执行时的出现的异常,则需要在子线程执行的代码中编写try/catch块来捕获异常,主线程中的try/catch不会对子线程中的异常起作用。 ​

前后台线程

一般情况下,创建的线程属于两类,即前后台线程

前后台线程退出:

线程优先级

线程存在优先级,优先级越高的线程越先被分配到时间片,即越先执行。 在需要的情况下,我们可能需要提升一些线程的优先级,以便应用程序正常运行。

信号

在一些情境下,我们需要线程按照我们的指示进行运行等待,这就需要信号。

多客户端应用程序

对于一些多客户端的应用,程序需要保持UI响应及时,同时又要处理计算等密集工作,这样的程序就需要多线程处理

同步上下文

通过同步上下文类可以进行子线程向主UI线程传递数据操作。 ​

0 人点赞