C#多线程和异步

什么是线程

线程是一个可执行的路径,他可以独立于其他线程执行。

每个线程在操作系统的进程内执行,而操作系统提供了程序的运行独立环境。

单线程指的是环境中跑了一个线程,所以该线程拥有独占权。

多线程应用,单个进程中会跑多线程,他会共享当前执行环境。

线程的一些属性

线程一旦开始执行,isAlive就是true,线程结束就是false;

线程结束的条件就是,线程构造函数传入委托结束了执行。

线程一旦结束局无法重启。

线程都有个name属性用来调试。

静态的thread.currrentThread属性,会返回当前执行的线程。

 

多线程目的是为了处理复杂耗时的工作,设置不同的线程处理不同的工作是能提高效率的方法。

线程生命周期:起始(System.Threading.Thread类被创建),结束(线程被终止)。

生命周期中的状态:

1.创建但为使用:创建好了线程但没使用start调用。

2.就绪状态:当线程准备好运行等待CPU周期状态

3.不可运行状态:①调用sleep。②调用了wait。③I/O阻塞。

4.死亡状态:线程执行完毕关闭了。

主线程:C#在执行的时候第一个线程就是主线程,也是自动创建的。

 

public static void CallToChildThread()
{
    try
    {

        Console.WriteLine("Child thread starts");
        // 计数到 10
        for (int counter = 0; counter <= 10; counter++)
        {
            Thread.Sleep(500);
            Console.WriteLine(counter);
        }
        Console.WriteLine("Child Thread Completed");

    }
    catch (ThreadAbortException e)
    {
        Console.WriteLine("Thread Abort Exception");
    }
    finally
    {
        Console.WriteLine("Couldn't catch the Thread Exception");
    }

}
static void Main()
{
    ThreadStart childref = new ThreadStart(CallToChildThread);
    Console.WriteLine("In Main: Creating the Child thread");
    Thread childThread = new Thread(childref);
    childThread.Start();
    // 停止主线程一段时间
    Thread.Sleep(2000);
    // 现在中止子线程
    Console.WriteLine("In Main: Aborting the Child thread");
    childThread.Abort();
}

这里只是线程的体现,一般不会这样使用。

 Join and sleep

调用join方法,就可以等待另一个线程的结束。

调用join的时候,可以设置一个超时,使用毫秒或者TimeSpan。

调用sleep就是等待

注意:Thread.Sleep(0)这样调用会导致线程放弃本身的时间片,自动将cpu移交给其他线程。

阻塞:如果线程的执行由于什么原因导致暂停,就是线程阻塞了。

被阻塞的线程会立即将处理器的时间片交个其他线程,从此就不在消耗处理器的时间,直到满足阻塞条件。

 可以通过ThreadState这个竖向判断线程是否被阻塞

bool blocked=(someThread.ThreadState & ThreadState.waitSleepJion)!=0

 

ThreadState 属性的取值如下:

Aborted:线程已停止;

AbortRequested:线程的Thread.Abort()方法已被调用,但是线程还未停止;

Background:线程在后台执行,与属性Thread.IsBackground有关;

Running:线程正在正常运行;

Stopped:线程已经被停止;

StopRequested:线程正在被要求停止;

Suspended:线程已经被挂起(此状态下,可以通过调用Resume()方法重新运行);

SuspendRequested:线程正在要求被挂起,但是未来得及响应;

Unstarted:未调用Thread.Start()开始线程的运行;

WaitSleepJoin:线程因为调用了Wait(),Sleep()或Join()等方法处于封锁状态;

 

 

解除阻塞:

但遇到下面四种情况才解除阻塞

1.阻塞条件满足

2.操作超时

3.通过Thread.Interrupt()进行打断

4.通过Thread.Abort()进行中止

 

IO-bound和Compute-bound

一个话费大量时间去等待某件事发生叫做IO-bound

IO-bound绑定操作通常涉及输入输出,但不是硬性要求,Thread.Sleep()也被叫做IO-bound

IO-bound也可以是干等这,什么也不干

相反,话费大量时间执行cpu密集工作的叫做Compute-Bound

compute-bound就是指的很忙,没时间

 

阻塞和忙等待:Blocking and Spinning

IO-bound操作工作方式有两种:

  在当前线程上同步等待:Console.ReadLine(),Thread.sleep(),

异步操作,稍后操作完等待回调

忙等待:while(DateTime.Now<nextStartTime);

忙等待和阻塞有些差别:

希望时间短,就考虑忙等待.net framework 提供了特殊的方法SpinLock和SpinWait

其次,阻塞线程成本比较高,会带来额外开销(上下文切换,会有2微秒)

因此,处理大量的IO-bound,阻塞很麻烦,所以需要基于回调,等待时期撤销线程。

 

本地VS共享状态

CLR为每个线程分配了自己的内存占(stack),以便本地变量保持独立

共享:

如果多个线程都引用同一个对象实例,那么就共享数据

被lambda表达式活匿名委托捕获的变量,也是公用的

静态字段

 

posted @ 2019-10-11 17:06  蔡老板2019  阅读(378)  评论(0编辑  收藏  举报