美文网首页
.Net 多线程

.Net 多线程

作者: 王清水 | 来源:发表于2021-02-10 18:53 被阅读0次

    CPU核心数量拥有成千上万的线程,一个线程负责执行一个任务,可分为原生线程和托管线程;【寄存器 < 逻辑核心 < CPU】

原生线程:

    我们将操作系统管理的线程称为原生线程,CPU中的逻辑核心都有N个寄存器,核心根据寄存器从内存中读取指令并运行一段机器码(某逻辑的处理内容),所以,单个逻辑核心同一时间只能执行一个线程(线程切换执行),线程切换可分为主动切换,比如线程内任务完成或IO读取文件等行为主动暂停运行,以及被动切换,即硬件计时器时间片时间超时后,将被动切换;

    CPU中各个寄存器的数据结构则成为上下文,而线程切换称为上下文切换;上下文切换的成本主要在于上下文数据的保存;

原生线程切换

托管线程

    .Net Core基于原生线程搭建的线程模型,由.Net Core管理的线程;

    一个托管线程只能管理一个原生线程,可以为 0:1 (未开始、未关联线程的线程)或 1:1的关系,一个Thread对象就关联一个原生线程; 
    ==> 1,托管代码创建中,只有调用Start方法后,才会创建新的原生线程并关联线程对象;
    ===>2,.Net运行时内部使用时,将同时创建;
    ===>3,非托管代码在原生线程上首次调用托管代码时将创建和关联
    ===>4,Main函数运行

    .Net提供了标准的线程操作接口,

托管线程

    GC 找出存货的对象,清理没有引用的对象,负责执行 ;   
    扫描和清理对象的GC线程(需要停止其他线程运行,实际为GC切换合作模式到抢占模式);
    负责分配对象或改变对象引用关系的其他线程;

    为了处理上述的矛盾关系:
        ==>抢占模式,不能访问托管堆上的对象,需要等待GC结束,切换到合作模式
        ==>合作模式,可自由访问托管堆上的对象,所以,托管代码需要在合作模式下运行

    托管代码切换:
        ===>主动切换,线程自己切换,托管代码通过P/Invoke嗲用非托管代码 
        ===>被动切换,一个线程切换其他线程的模式,GC线程切换其他线程到抢占模式

    线程切换时,GC应该处于安全点,JIT编译器在生成托管汇编代码时会生成元数据,元数据中包含GC信息,该信息包含了线程运行到某条指令时,哪个位置有应用类型的对象,这些对象将会被作为根对象扫描;

    步骤:暂停线程 => 分析线程是否处于GC安全点

前台线程和后台线程

    Thread创建的都是前台线程,当后台线程全部完成后,前台线程才会结束

线程本地存储

    线程内部的相关数据结构,使用特性[ThreadStatic],保持线程间的数据独立性;

    通过分段寄存器(上下文一部分)访问到独立的线程存储;

    TLB表(Thread Local Block),使用AppDomain ID作为索引保存 TLM表(Thread Local Module)=> 以模块ID为索引记录托管线程本地存储空间的开始地址

线程本地存储1 线程本地存储2

原子操作

    多线程存在同时访问一个资源,这时,需要一种不可分割且其他原子操作互斥的操作;

    .Net 中 Interlocked类提供了对原子操作的相关方法,结合线程锁(适用于复杂的逻辑操作)/无锁算法就能实现资源同一时间只被一个线程使用;【无锁算法通过修改算法结构来抛弃使用线程锁而达到原子操作,如.Net中的Concurrent...开头的线程安全的数据结构】

    锁:
        ==>自旋锁,基于原子操作,0表示未获取,1已被获取,循环检查锁是否被释放,Thread.SpinWait()可实现一个自旋锁;自旋锁应该在较短的时间内完成任务,否则将长期占用CPU运算核心,而且会造成权重高的线程可能得不到核心计算;所以,处理这种情况可以使用排队自旋锁;自旋锁拥有高性能的处理能力;这里也可以使用new SpinWait().SpinOnce()和SpinLock;.Net性能的提高其实很多的地方都改用了这些自旋锁,不适用于长时间运行的操作;
        ==>互斥锁,获取锁失败时,不重试,而是进入等待,放入等待队列;在线程状态切换(从等待-唤醒-运行)对比自旋锁是很消耗时间的;
        ===>信号量,Semaphore类,可跨进程使用(SemaphoreSlim类非跨进程);使用线程管理的方式,对多个线程进行锁的应用操作;
        ===>读写锁,频繁读取并需要一定时间的场景,分为读取锁、写入锁,实质相当于一个混合锁,在自旋次数后,进入线程等待队列中等待,保证 读取锁、写入锁会同时存在同一线程

Thread.Sleep()、Thread.Yield 在Windows下

    Sleep()方法:调用系统SleepEx,切换到任意核心关联的带运行队列中的线程,如果参数设置为0;

    Yield():当前逻辑核心关联的待运行队列中的线程;

    如果是Linux系统,则两者没有区别

相关文章

  • .Net 多线程

    CPU核心数量拥有成千上万的线程,一个线程负责执行一个任务,可分为原生线程和托管线程;【寄存器 < 逻辑核心 < ...

  • Java网络知识汇总

    Java多线程https://blog.csdn.net/qq_35114086/article/details/...

  • Android知识点

    Android多线程安全:https://blog.csdn.net/SenchunHuang/article/d...

  • GCD多线程并发执行多任务并同步返回

    前面有写过一篇 .NET 使用WaitHandle开启并发多线程查询并同步返回 在.NET中有WaitHandle...

  • node优缺点

    优点: 多线程,高并发http://blog.csdn.net/xiaemperor/article/detail...

  • QT多线程

    QT多线程[https://blog.csdn.net/weixin_42126427/category_1017...

  • 线程+线程池+使用

    Android 多线程: 完全解析线程池ThreadPool原理&使用https://blog.csdn.net/...

  • .NET多线程(十二)WinForm

    本节主要内容 ** WinForm 跨线程更新UI ** 通过UI线程的SynchronizationContex...

  • .NET多线程(十一)Socket

    一、 Socket服务端 单个TCP/IP端口上能够被多少个进程侦听?可以为多个,这时候是端口复用 WCF需要打...

  • .NET多线程(二)线程

    本节主要内容 命名空间 线程的创建 使用构造函数 线程的挂起、阻塞、终止 将【当前线程】挂起指定的时间。 将【调用...

网友评论

      本文标题:.Net 多线程

      本文链接:https://www.haomeiwen.com/subject/moxhxltx.html