上交os lec5进程与线程
5.1进程的基本概念
5.2进程的基本操作接口
- fork的父子进程共享一个指向文件的结构体那么它们共享的文件体中的读写指针也是一样的,这个是posix标准,read系统调用在linux实现会加??
- fork为进程之间建立了进程树多个进程属于同一个进程组,进程组的作用是,可以向同一个进程组的所有进程发送信号
- fork的缺点是:1.完全拷贝比较耗时,即使是cow中只建立映射,也很耗时 2.在fork的时候必须得持有fork的??,因为在fork的时候必须保证父进程的状态不变,所以fork多个进程的时候,只能够逐个fork 3.不可组合性,fork() + pthread(),如果先去pthread()创建一系列的线程,之后再fork会发送什么?
- vfork会让父子进程共享同一空间,连映射(页表项)都不需要拷贝了,但是它只能用在fork + exec的场景中,并且共享地址空间存在安全问题,有些时候,vfork可以用来实现线程,因为线程之间就是共享地址空间
- posix_spawn相当于fork + exec;clone可以选择性的不拷贝内存
5.4线程的基本概念
- 创建进程的开销比较大;进程的隔离性过强,导致IPC开销较大;进程内部无法并行
- 每一个线程都有自己的内核栈与用户栈,并且是在进程的虚拟地址空间之中
- 内核态线程与用户态线程(纤程/协程)线程模型
- 多对一线程模型,内核态线程才能够去被调度,分配对应的线程资源,对于这种模型,多个用户态线程就不能够在多个核上并行运行了,也就是一个用户态进程阻塞了,这个内核态线程对应的用户态线程都会阻塞,也就是可扩展性差
- 一对一模型,缺点是开销大,每一个用户态线程都要对应于一个内核线程,内核开销大,这一个就是linux中不存在协程的概念的原因吧?
- 多对一模型
- TCB,线程相关的数据结构
5.5线程本地存储和上下文切换
- 对于不同的线程,进程中的全局变量需要不同的拷贝,所以需要线程本地存储(TLS)
- 每一个线程都有一个特殊的寄存器,里面存的是TLS的基地址
- pthread_create创建新的线程,包括内核态与用户态pthread_join可以认为是fork的逆向操作pthread_exit是退出线程,可以和pthread_join配合,pthread_yield可以帮助调度器做出更优的决策
- 内核栈的切换是线程切换的分界点
5.6 纤程
- 一对一线程模型花销大,同时,对于运行时间短的线程,如果也需要一个内核线程,那么其初始化时间长,线程上下文切换频繁,比如一个手机里的线程时常几百乃至上千个
- 用户态线程,也就是纤程,比线程更加轻量级的运行时抽象
- linux即使是一对一的模型,也能够创建协程
- 在linux中一个生成者消费者的例子,协程的一大好处就是可以在协程切换的时候,不需要陷入内核,开销小由于不需要使用内核线程的调度器,纤程的切换总是可以是最优调度
- 不适合协程的情况有调用库函数,库函数其中会调用系统调用,并且有可能会阻塞,如果一个协程阻塞了,比如sleep,或者while(1),那么同一个线程的其他协程也会被阻塞
- windows中存在与linux中类似的编程模型,并且纤程也可以存储本地变量FLS
- 协程也存在多个状态