操作系统线程

一、引入线程

操作系统有了进程为何要出现线程呢?

        操作系统中可以使用进程来描述一个程序的执行过程,进程拥有该程序的所有数据(包括一些I/O分配情况、内存分配情况等),也就是该程序的一个载体,所以进程有一个特点就是资源分配的单位,这一点十分重要。进程还有一个特点就是调度执行,交替执行以提高资源利用率……。

        操作系统管理进程(创建、切换进程、分配与回收……)开销是很的,比如进程创建时还需要创建PCB,分配内存独立的内空间,建立映射表,创建资源……,进程切换时还需要切换资源,如切换对应的内存映射表,进程退出时还需要释放资源。

        此时操作系统就引出了线程(称为轻量级进程LWP),进程任然是资源分配的单位,但是调度执行却交给了线程,因为线程是在进程的内部,线程间的切换不用切换资源,不用切换映射表,只需要简单的在进程内部切换一下PC指针和保存一些寄存器即可,这也就更轻量了(避免不了不同进程间的线程切换)。

线程(Thread)既保留了并发执行的优点,也避免了进程切换的代价

举个例子:

有一个网络服务器,此时没有线程的概念,该服务器程序用到多个进程,如用一个进程监听客户端的请求,当客户端连接上后就分派出(复制出一个子进程)一个进程给该用户(每个进程都有独立的资源),用于监听该用户发送的数据并处理(即多进程程序),此时设想一下,这多个进程切来切去,每次切换的时候都需要切换资源,是不是很耗费资源。

再来看,此时如果出现了线程,网络服务器这个程序是一个进程,进程用于承载该程序的资源,首先用进程中的一个线程监听请求,每次连接客户端都分配一个线程给用户(多线程程序),此时处理器只需要在这几个线程中切换即可,线程的切换不需要切换资源(进程时资源级的切换,线程是指令级的切换),这多个线程只需要共享进程中的资源就行了,效率也得到了提升。

有时候多进程程序比多线程程序更高效,如果是多个进程或线程需要共享数据或需要统一协调,这种情况下一般多线程更有优势

线程的好处:

  • 线程的创建、终止和调度更轻量
  • 线程间的通信不进过内核,不需要用户态->内核态的转换

二、线程

每个线程都有:

  • 类似进程,线程也有执行状态(运行、就绪、阻塞……),因为线程也是一个执行过程
  • 线程的上下文,线程切换时也需要进行保护现场
  • 执行栈,保存系统调用时的一些参数和中间结果
  • 少量的,线程私有的局部变量的存储空间,不再拥有大量的存储空间
  • 与进程内其他线程共享的内存和资源的访问
  • 线程控制块TCB,存放上下文切换的信息,同PCB

 如上图是有线程和无线程的区别,其中用户栈用于保存用户进程的子程序间相互调用的参数、返回值以及局部变量等信息(保存普通方法的栈);内核栈是程序发生系统调用时内核态调用方法时的栈;用户地址空间则是进程的程序和数据存放的空间,线程是没有自己的用户地址空间的。

图中可以看到用户栈和内核栈已经在线程中独有了,也证明了线程成为了任务调度的基本单位,这些线程都共享进程所持有的资源,线程控制块中存放了寄存器的值、优先级、线程状态等信息。

由图可知,所有线程共享进程的状态和资源,所以线程都驻留在同一块地址空间中,并可访问相同的数据。

操作系统引入线程后,调度和分派是在线程上完成的,但是某些活动会影响进程中的所有线程,因此这些活动必须在进程级对他们进行管理。如挂起操作会挂起所有线程,因为所有线程共享进程的用户地址空间。

三、线程分类

线程分为用户级线程(User-Lever Thread,ULT)和内核级线程(Kernel-Level Thread,KLT),内核级线程有叫做轻量级进程

用户级线程

纯用户级线程

 在纯ULT软件中,管理线程的所有工作都是应用程序完成,内核意识不到线程的存在,线程完全是由线程库提供的,创建、销毁、调度线程、线程间传递消息等,还包括保存上下文都是由它管控的,如果可以的话我们自己也可以实现自己的线程库,只要合理的组织线程即可。

但是用户级线程所有的活动都发生在用户空间和一个进程中,系统感知不到用户级线程的存在,所以系统依旧是以进程的方式调度。

如下:

 当线程1发生系统调用等阻塞了,此时系统就会认为该进程阻塞了,操作系统会把CPU时间片分配给其他进程,在此期间,根据线程库维护的数据结构来看,线程1任然处于运行状态,但在处理器执行的角度,线程2是不处于运行状态的,也分不到时间片。

这也导致了用户级线程一旦阻塞,就会阻塞进程中的所有线程,使得其他线程也得不到运行。

使用ULT而非KLT的优点如下:

  • 所有线程的管理都在一个进程的用户空间中,线程的切换不需要内核模式特权,不需要系统调用,从而节省了用户态到内核态转换的开销
  • 线程的调度更灵活,可以为每个不同的应用程序量身定制更合适的调度算法,因为这些调度算法都可以自己实现,不需要更改操作系统底层的调度程序
  • ULT可以在任何操作系统下运行,即便是不支持线程的操作系统也能实现,线程库是供所有应用程序共享的一组应用级函数

缺点:

  • 在执行一个系统调用时不仅仅是阻塞当前线程,还会阻塞进程中的所有线程
  • ULT不能利用多处理技术,操作系统看不到线程,所以内核一次只能把一个进程分配给一个处理器,因此一个进程中的所有线程不能够并行执行,只能够并发执行,相当于一个进程内实现了多道程序设计

 解决这两个问题的方法有:

  1. 把应用程序写出多进程程序,但是该方法消除了线程的主要优点
  2. 套管技术:把产生阻塞的系统调用转化为一个非阻塞的系统调用

ULT适合计算密集型的,因为不需要IO操作 ,不会阻塞整个进程

内核级线程

纯内核级线程

 在KLT软件中,管理线程的所有工作均由内核完成,应用级没有线程管理代码,只有一个到内核线程的API。

内核为进程级进程内的所有线程维护上下文信息,调度由内核基于线程完成

该方法克服了ULT的两个缺点。首先,内核可以把一个进程中的线程分配个多个处理器中;其次,进程中的某个线程阻塞了,内核还可以调度同一个进程中的其他线程。

缺点是:在把控制权从一个线程传送到另一个进程的线程时,需要切换到内核模式,开销较大。

KLT并发性更好,适合I/O操作较多的程序

KLT中,进程调度实际就是线程调度

混合方式

组合

 有些操作系统提供了ULT和KLT的混合体线程创建完全在用户空间中完成线程的调度和同步也在应用程序中进行,一个应用程序中的多个用户级线程会被映射到一些(小于等于用户级线数)内核级线程上,进程和线程的比为 N:M,N<=M,ULT中比值为1:N,KLT为1:1

同一个应用程序中的多个线程可在多个处理器上并行的运行,某个引起阻塞的系统调用不会阻塞整个进程。

纤程(fiber):纤程由线程创建,运行在调度其的线程上下文中,且必须由应用程序调度的一个可执行单元,每个线程可以调度多个纤程。

参考书籍——操作系统精髓与设计原理

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值