Linux(高级编程)12————线程概念

2019-07-14 11:04发布

线程轻量级进程,那么线程到底是什么呢?
还记得我们前面在说进程时提到过PCB吗?其实在linux下PCB是对线程的描述。线程是轻量级进程,是一个进程内部的一条执行流。确切的说,linux下线程是以进程PCB来模拟的,所以前面说linuxPCB其实是对线程的描述,那么Linux下的进程又是什么呢?linux下的进程在此时就是一个线程组,因此线程是一个轻量级进程。
一个进程内可能有多个线程,这些线程多使用相同的虚拟地址空间,因此线程的调度切换是在进程的地址空间里切换的,因此相较于进程切换的成本低一点。
一个进程中的多个线程共享相同的虚拟地址空间,那么相较于进程的创建与销毁,线程的成本要低一点
线程之间共享虚拟地址空间也使得线程间的通信变得方便。
  • 画一幅图理解线程与进程间的关系,同时也能加深的线程理解:
    在这里插入图片描述
  • 进程与线程:
    进程是操作系统资源分配的最小单位,线程是进程内部的一条执行流也是因为这个原由,这同时也是多个线程之间共享相同虚拟内存空间的原因。线程是CPU调度和分配的基本单位,它是比进程更小的可以单独运行的基本单位。
    进程间通信我们有前面提到过的几种方式,但我们可以想到多个线程之间共享虚拟内存空间,那么他们之间的通信是不是会变得方便呢?答案是:是的。
    上面这幅图可以看出多个线程之间共享虚拟内存空间,进程数据段的数据在线程之间也是共享的,存储在代码段的内容是共享的,全局变量也是共享的;那么除此之外线程之间到底还共享了那些内容呢?
    • 文件表述符
    • 每种信号的处理方式
    • 当前用户工作目录
    • 用户ID和组ID
    除了线程之间共享的数据,它们也是具有一定的“个性”的,也就是拥有它们自己的一部分:
    • 线程ID
    • 上下文信息,各种寄存器的值,程序计数器和栈指针。(由于线程间是并发运行的,每个线程有自己不同的运行线索,当从一个线程切换到另一个线程上时,必须将原有的线程的寄存器集合的状态保存,以便将来该线程再被切换到时能够恢复之前运行的现场)。
    • 信号屏蔽字
    • errno值
  • 总结:
    进程与线程的区别
    • 进程是系统分配资源的最小单位;线程是CPU调度的基本单位。
    • 进程拥有自己独立进程地址空间,而线程是在进程地址空间之上存在,故同一进程中多个线程共享资源。
    • 创建进程的开销是比较大的,需要为进程创建PCB,为进程分配资源,而线程的创建只需要在进程内部将一部分线程独享的资源分配给线程。
    • 进程具有独立的进程虚拟空间使得多进程程序的健壮性更好;由于多线程之间共享资源,导致一个线程出错会是整个程序(进程)出错。
    • 进程间的切换比线程间的切换代价大,进程间切换需要切换页表和进程的上下问切换,而线程间的切换实质上实在同一份页表上进行的,只需要在进程内部进行线程的上下文切换。
    • 因为线程之间共享资源(进程间地址空间)也导致了线程安全变的尤为重要;同时也使得线程间通信变的简单,但也带来了多线程编码难度增大问题。
    多线程与多进程的应用场景:
    • 多线程:高响应(即像服务器这样的程序,需要快速为客户提供服务时选择多线程,因为线程的创建与销毁成本低)、用户访问量多、对程序的健壮性要求并不是很高的程序。
    • 多进程:对程序的健壮性要求高(一个服务的进程挂掉,其它今后进程仍然可以正常工作),创建与销毁并不是很频繁的程序。
用户线程和内核线程的理解:
线程可分为两种:用户态线程和内核态线程。内核态线程,在有的系统上也称为LWP(light weight process 轻量级进程),运行在内核空间,有内核cpu调度。当进程的一个内核线程获取cpu的使用权时,它就加载并运行用户态线程。可以看作:用户态线程是在内核态这个“容器”上运行的,即用户态线程依托于内核态线程(这个内核态线程即就是进程本身),一个进程可以拥有M个内核线程和N个用户态线程,其中M<=N。并且一个系统的所有进程,M和N的比值都是固定的。
线程模型的实现可分为三种,分别为:1.完全用空间线程 2.完全内核调度线程 3.双层调度
完全在用户空间:
1.无需内核支持,内核根本不知道这些线程的存在,由线程库管理所有线程的(创建,调度,销毁),如:时间片、优先级。
2.线程库切换线程,使他们看起来像“并发”执行的,但实际上内核仍然是把整个进程作为最小单位来调度的,所有线程共享该进程的时间片(此时线程调度有进程自定义),它们对外表现相同的优先级,即M个用户态线程对应1个内核线程,而这个内核线程实际上是进程本身。
优点:
1.用户线程可以在不支持线程的操作系统上实现。
2.线程切换比内核切换要快。
3.允许每个进程有自己定制的调度算法
缺点:
1.用户线程发生I/O或页面故障引起的阻塞时,如果调用阻塞系统调用,则整个进程都会陷入阻塞状态。
2.对于多处理器系统,一个进程的多个用户线程无法运形在不同的cpu上,因为内核是按照起最小调度单位来分配cpu的。(无法充分利用多处理器资源)。
内核态线程:
1.完全有内核调度的模式创建、调度线程的任务交给内核,运行在用户空间的线程无需执行管理任务。
2.它们相较于用户态线程开销较大。
优点:
1.当线程中的某个发生阻塞时,其它线程仍然可以正常工作,不会影响正常整个进程。
2.多处理器系统中,能够充分利用处理器资源。
缺点:
线程的切换相较于用户线程开销较大(原因:从内核态切换到用户态需要耗费较多的时间)。
双层模型:
结合用户态线程和内核态线程的优缺点,采用内核态调度M个内核线程,线程库调度N个用户线程,这样不但不会消耗过多的内核资源,而且线程切换速度也较快,同时能够充分利用多处理器的优势。