zoukankan      html  css  js  c++  java
  • 多线程(1)认识多线程

      多线程在项目开发过程中非常非常重要,这个系列就来详细总结一下,首先认识一下多线程。

    windows为什么要支持多线程

    计算机的早期时代,操作系统没有线程的概念,整个系统只运行着一个执行线程,其中包含操作系统代码和应用程序代码。只用一个执行线程的问题在于,长时间运行的任务会阻止其他任务的执行。例如16位Windows的时代,打印文档的应用程序很容易“冻结”整个机器。

    Microsoft 在设计Windows NT这个版本的OS内核时,决定在一个进程中运行应用程序的每个实例。进程实际是应用程序的实例要使用的资源的集合。每个进程都被赋予了一个虚拟地址空间,确保一个进程中使用的代码和数据无法由另一个进程访问。这就确保了应用程序实例的健壮性。同时,进程访问不了OS的内核代码和数据;所以,应用程序代码破坏不了操作系统的代码和数据

    如果应用程序发生死循环会发生什么?如果机器只有一个CPU,它会执行死循环,不能执行其他任何程序。Microsoft 的解决方案就是线程。作为一个Windows概念,线程的职责是对CPU进行虚拟化。Windows为每个进程都提供了该进程专用的线程(功能相当于一个CPU)。应用程序的代码进行死循环,与代码关联的进程会“冻结”,但其他进程(它们有自己的线程)不会冻结,它们会继续执行。
    线程很强大,因为它们使Windows即使在执行长时间运行的任务时,也能随时响应。

    所以多线程的发展历史可以简单总结为:没有线程(只有一个执行线程)--->引入进程--->引入多线程 

    线程的开销

    线程是给我们带来好处的同时,也有性能的损失,包括空间上和时间上的。

    1,空间上

    创建一个线程需要加载以下资源:

    • 线程内核对象(thread kernel object),操作系统为系统中创建的每个线程都会分配并初始化这种数据结构,主要用于描述线程的属性和线程上下文,上下文是一个内存块,其中包含了CPU的寄存器集合。对于X86,X64和IA64的CPU来说,分别要使用700,1240和2500字节的内存。
    • 线程环境块(thread environment block,简称TEB),TEB是在用户模式(应用程序能快速访问的内存地址)中分配和初始化的一个内存块,TEB耗用1个内存页(X86和X64 CPU中是4KB,IA64 CPU是8KB)。
    • 用户模式栈(user-mode stack),用户模式栈用于存储传给方法的局部变量和实参,它还包含一个地址,指出当前方法返回时,线程接着应该从什么地方执行,默认情况下,windows为每个线程的用户模式栈分配1MB内存。
    • 内核模式栈(kernel-mode stack),当应用程序代码向操作系统中的一个内核模式的函数传递实参时,就会使用到内核模式栈。出于安全的考虑,Windowd会把这些实参从线程的用户模式栈复制到线程的内核模式栈。32windows 内核模式栈大小12KB,64位是24KB。
    • DLL线程连接(attach)和线程分离(detach)通知,Windows的一个策略是,任何时候在进程中创建线程,都会调用进程中加载的所有非托管DLL的DllMain方法,并向该方法传递DLL_THREAD_ATTACH标志。同样的,任何时候线程终止,都会调用进程中的所有非托管DLL的DllMain方法,并向该方法传递DLL_THREAD_DETACH标志。

    2,时间上

    因为windows要在系统中的所有线程(逻辑CPU)之间共享物理CPU。在任何给定的时刻,windows只将一个线程分配给一个CPU,那个线程能运行一个“时间片”的长度。时间片到期,Windows就将上下文切换到另一个线程。

    每个时间片的切换,windows都需要大概30ms的时间。

    为什么要使用多线程

    1,可响应性,或称用户体验,一般针对winform程序,可以将一些耗时的任务交给另一个线程去处理,使GUI线程能灵敏地响应用户的输入和操作。否则,界面会比较卡。

    2,提升性能,由于windows每个CPU调度一个线程,多个CPU能并行调度线程,所以可以同时执行多个任务,从而提升性能。 

    进程,线程和应用程序域的关系

    在进一步学习多线程之前,很有必要来了解一下这三个概念,以及其中的关系。

    1,名词解释

    进程

    或称Process,可以简单理解为一个.exe的实例。进程是windows系统中的一个基本概念,它包含着一个运行程序所需要的资源。进程之间是相对独立的,一个进程无法访问另一个进程的数据(除非利用分布式计算方式),一个进程运行的失败也不会影响其他进程的运行,Windows系统就是利用进程把工作划分为多个独立的区域的。进程可以理解为一个程序的基本边界。

    线程

    或称Thread,可以简单理解为虚拟CPU。线程是进程的基本执行单元,在进程入口执行的第一个线程被视为这个进程的主线程。在.NET应用程序中,都是以Main()方法作为入口的,当调用此方法时系统就会自动创建一个主线程。线程主要是由CPU寄存器、调用栈和线程本地存储器(Thread Local Storage,TLS)组成的。CPU寄存器主要记录当前所执行线程的状态,调用栈主要用于维护线程所调用到的内存与数据,TLS主要用于存放线程的状态信息。

    应用程序域

    或称AppDomain,可以简单理解为一组程序集的逻辑容器。CLR在初始化在初始化时创建第一个AppDomain(默认AppDomain),这个AppDomain在进程终止时被销毁。.NET的程序集正是在应用程序域中运行的。一个进程可以包含有多个应用程序域,一个应用程序域也可以包含多个程序集。

    2,进程,线程和应用程序域的关系

    可以用以下两幅图和两句话来总结。

    1),一个进程可以包含多个线程和应用程序域。

    2),一个线程可以穿梭在多个应用程序域中,但在某个时刻,线程只会处于一个应用程序域内。 

    前台线程和后台线程的区别

    1,前台线程和后台线程的区别在于,应用程序必须运行完所有的前台线程才可以退出,而对于后台线程,可以不考虑其是否运行完而直接退出并且不会抛出异常,所有的后台线程在应用程序退出时就自动结束了。

    2,默认情况下,主线程和使用Thread创建的线程都是前台线程(使用线程池和Task创建的线程默认都是后台线程),除非手动设置IsBackground= true。

    多线程和异步的区别

     多线程和异步在很多时候被认为是同一个东西,都是为了让主线程不需要等待而继续执行。

    但是从辩证关系上来看,两者还是有区别的,可以用一句话来概括。

    异步是目的,多线程是实现异步的其中的一种方式(比如还可以通过创建另一个进程实现异步)。

  • 相关阅读:
    vue使用elementui合并table
    使用layui框架导出table表为excel
    vue使用elementui框架,导出table表格为excel格式
    前台传数据给后台的几种方式
    uni.app图片同比例缩放
    我的博客
    【C语言】取16进制的每一位
    SharePoint Solution 是如何部署的呢 ???
    无效的数据被用来用作更新列表项 Invalid data has been used to update the list item. The field you are trying to update may be read only.
    SharePoint 判断用户在文件夹上是否有权限的方法
  • 原文地址:https://www.cnblogs.com/mcgrady/p/7053674.html
Copyright © 2011-2022 走看看