- 日期:20160606
- 作者:i.sshe
- https://github.com/isshe
操作系统之进程线程
1. 问题列表
- 1.1 什么是进程?什么是线程?
- 1.2 进程的基本状态及转换?
- 1.3 进程控制块(PCB)?
- 1.4 进程的运行模式有哪些?
- 1.5 进程间是如何通信的?
- 1.6 系统如何将一个信号通知给进程?
- 1.7 32/64位系统一个进程最多能拥有多少堆内存?
- 1.8 如何实现守护进程?
- 1.9 线程控制块(TCB)?
- 1.10 线程有哪些状态?
- 1.11 线程为什么没有挂起状态?
- 1.12 什么是用户级线程?什么是内核级线程?有何优缺点?
- 1.13 进程和线程的区别?
- 1.14 线程中可以创建线程吗?
- 1.15 线程中可以创建进程吗?
- 1.16 线程的同步机制有哪些?
- 1.17 什么是僵尸进程?什么是孤儿进程?
2016.11.1补充
* 1.18 fork后,子进程继承父进程的什么,父、子进程区别?
2. 拓展问题
- 2.1 什么是上下文?上下文切换又是什么?
- 2.2 堆和栈的区别?
- 2.3 试解释操作系统原理中的作业、进程、线程、管程的定义?
3. 解答
3.1 什么是进程?什么是线程?
- 进程
- 定义:一个执行中的程序的实例.
- 是一个可拥有资源的独立单位;
- 是操作系统对一个正在运行的程序的抽象;
- 是计算机科学中最重要最成功的一个概念;
- 在一个系统上可以上可以同时运行多个进程;
- 线程
- 调度和分派的基本单位;(只有一些必要的资源,所以也称为"轻型进程")
- 一个进程内可以创建多个线程;(每个线程都运行在进程的上下文中,并共享的代码和全局数据)
3.2 进程的基本状态及转换?
- 三种基本状态:
- 就绪状态(Ready). 资源什么的已经准备好了,只要得到处理机就可进入执行状态.
- 执行状态(Running).
- 阻塞状态(Block). 资源没有得到满足.
- 引入的状态:
- 创建状态.
- 终止状态.
- 挂起状态.(下图没有画进去)
- 状态间的转换:
3.3 进程控制块(PCB)
- 进程控制块:操作系统维护的一张进程表.
- 包含的一些字段:
- 进程管理: 寄存器, 程序计数器,程序状态字, 堆栈指针, 进程状态, 优先级, 调度参数, 进程ID(唯一), 父进程, 进程组, 信号, 进程的开始时间, 使用的CPU时间, 子进程的CPU时间, 下次报警时间.
- 存储管理: 正文段指针, 数据段指针, 堆栈段指针.
- 文件管理: 根目录, 工作目录, 文件描述符, 用户ID, 组ID.
3.4 进程的运行模式有哪些?
- 进程的工作模式有两种: 内核模式(态)和用户模式(态).
- 处理器通常通过模式位(mode bit)来设置进程运行模式,设置模式位的时候运行在内核模式, 否则运行在用户模式.
用户模式到内核模式的方法:
- 中断
- 故障
- 陷入系统调用
内核模式到用户模式:
- 处理程序运行在内核模式中,当它返回到用户程序代码时,就会切换.
3.5 进程间是如何通信的?
- Linux支持的进程间通信机制包括:管道,信号,消息队列,内存共享, 快速用户空间互斥体(futex:fast userspace mutex)等。
- http://blog.csdn.net/i_scream_/article/details/51619428
3.6 系统如何将一个信号通知给进程?
- 信号是软件中断!
- 当系统检测到某软件条件(如SIGURG, SIGPIPE, SIGALRM等,因为是软件中断,所以是软件条件)发生时,将其对应的信号通知给有关进程,并执行特定操作(注册信号时指定的操作)。
3.7 32/64位系统中, 一个进程分别最多能拥有多少堆内存?
- 不懂。
- 网上一种说法是:32位系统中,最大堆内存约等于虚拟内存减1G;
3.8 如何实现守护进程?
- 编程规则:(unix环境高级编程P374)
- 首先,调用umask将文件模式创建屏蔽字设置为一个已知的值(通常是0);
- 调用fork(),再exit父进程;
- 调用setsid创建一个新会话;
- 这里会发生三件事:
- 进程成为新会话的首进程;
- 进程成为新进程组的组长进程;
- 进程没有控制终端;
- 这里会发生三件事:
- 将当前工作目录更改为根目录;(因为从父进程继承过来的目录可能在一个挂载的文件系统中,如果不更改为根目录,则所挂载的文件系统不能卸载)
- 关闭不需要的文件描述符;
- 某些守护进程打开/dev/null使其具有文件描述符0, 1, 2。(守护进程不需要交互式输入/输出)
3.9 线程控制块(TCB)
- 每个线程都有自己的线程控制块(TCB),包括:
- 线程ID(TID,唯一,整数)
- 栈(如同非线程系统上的进程栈,主要存局部变量,参考…[此处有地址….])
- 栈指针
- 程序计数器
- 通用目的计数器
- 条件码(即各种状态标志)
- 所有运行在一个进程里的线程共享整个虚拟地址空间.(代码段开始虚拟地址为0x00400000[64bit], 0x08048000[32bit])
- 共享进程的代码段,数据段.
3.10 线程有哪些状态?
- 线程和进程都有三个基本状态.且情况一样.
3.11 线程为什么没有挂起状态?
- 挂起: 将资源从内存移动到外存.
- 线程不拥有资源,不管理资源,所以它应有将整个进程或自己本身从主存移动到外存的权限.
3.12 什么是用户级线程?什么是内核级线程?有何优缺点?
1). 用户级线程(ULT)
- 由用户应用程序建立,调度,管理, 操作系统不知道用户级线程的存在.
- 优点:
- 转换的时空开销比内核级线程小得多;
- 线程的调度算法和操作系统的调度算法无关;
- 适用于任何操作系统, 因为它与内核无关;
- 缺点:
- 无法利用多处理器的优点, 每次只有一个进程的一个线程在一个CPU上运行.
2). 内核级线程(KLT)
- 所有线程的创建,调度,管理都由操作系统内核负责.
- 优点
- 内核可调度一个进程中的多个线程, 可利用多处理器的优点.(同时在多个处理器上运行,提高程序的执行速度和效率);
- 当一个进程中的一个线程被阻塞,进程中的其他线程仍可执行;
- 内核本身也可以以线程的方式实现;
- 缺点:
- 线程切换时空开销大:同一个进程中的线程切换需要两次模式转换(用户态->内核态->用户态),因为线程调度程序运行在内核态,用户应用程序运行在用户态.
3.13 进程和线程的区别?
- 调度:
- 线程是调度和指派的基本单位; 进程是拥有资源的基本单位;
- 同一进程中,线程切换不会引起进程切换; 不同进程中, 线程切换会引起进程切换.
- 拥有资源:
- 线程不拥有系统资源,但可以访问隶属进程的系统资源.
- 进程拥有资源
- 并发性:
- 线程具有更好的并发性
- 切换开销:
- 线程开销更小,因为只需保存和设置少量寄存器的内容.
- 通信:
- 同一进程内的多线程通信更容易实现,但也容易出错.
3.14 线程中可以创建线程吗?
- 可以。
- 当一个程序启动时,就有一个进程被操作系统(OS)创建,与此同时一个线程也立刻运行,该线程通常叫做程序的主线程(Main Thread)。不知是否所有操作系统都适用?
3.15 线程中可以创建进程吗?
- 可以。程序开始的时候就会创建一个主线程用于执行代码。
- 如果线程中用exec系列的函数,则整个进程被替换。
- 如果线程用fork(),则可以。
3.16 线程的同步机制有哪些?
http://blog.csdn.net/i_scream_/article/details/51619428
3.17 什么是僵尸进程?什么是孤儿进程?
- 孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
- 僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵尸进程。
3.18 fork后,子进程继承父进程的什么,父、子进程区别?
- APUE p185
继承:
- 读写锁、条件变量、互斥量(这行自己加的、不知道该归哪类)
- 实际用户ID、实际组ID、有效用户ID、有效组ID。
- 附属组ID
- 打开文件
- 会话ID
- 控制终端
- 设置用户ID标志、设置组ID标志
- 当前工作目录
- 根目录
- 文件模式创建屏蔽字
- 信号屏蔽和安排
- 对任一打开文件描述符的执行时关闭(close-on-exec)标志
- 环境
- 连接的共享存储短
- 存储映像
- 资源限制
父、子进程区别:
- fork的返回值不同
- 进程ID不同
- 子进程的tms_utime、tms_stime、tms_cutime和tms_ustime的值设置为0(8.17节)
- 子进程不继承父进程设置的文件锁。!!!
- 子进程的未处理闹钟被清除。
- 子进程的未处理信号集设置为空集。
4. 拓展解答
4.1 什么是上下文?上下文切换又是什么?
- 操作系统保持跟踪进程运行所需的所有状态信息,这种状态,称为上下文.
- 无论是在单核还是多核系统中,一个CPU看上去像是在并发地执行多个进程,这是通过进程切换实现的.操作系统把这种交错执行的机制称为上下文切换.
4.2 堆和栈的区别
- 堆(从低地址往高低至增长): 所使用的局部变量还是在栈上,内容则在堆上.手动释放或者程序结束时由操作系统释放回收.
- 由程序员分配管理[new/malloc/realloc/calloc].
- 栈(从高地址往低地址增长): 局部变量/局部常量(const)[局部只读变量]/函数调用时返回地址/调用者的环境信息(例如某些机器寄存器).
- 由编译器自动分配释放管理.
- 关于C/C++程序运行时进程的内存分布情况
4.3 试解释操作系统原理中的作业、进程、线程、管程的定义?
- 作业:用户在一个事务处理过程中要求计算机系统所做的工作的集合。包括用户程序、数据、控制命令等,作业是由一系列有序的步骤组成的。
- 进程:一个程序在一个数据集合上的一次运行过程。
- 线程:进程中的一个实体,是被系统独立调用和执行的基本单位。
- 管程:一个数据结构+在该结构上能为并发进程所执行的一组操作,这组操作能同步进程和改变管程中的数据。
5. 零碎的概念/知识
- 调度: 内核可以决定抢占当前进程, 并重新开始一个先前被抢占的进程, 这种决定叫调度.由内核中呗称为”调度器”的代码完成.
- 父进程ID为0的各进程通常是内核进程(0代表内核),它们作为系统引导装入过程的一部分启动。
- linux中,进程和线程的执行效率是基本相当的。(进程只比线程多了个COW(copy on write)的开销)
- COW技术:写时拷贝。子进程和父进程要更改内存页面时,再拷贝一份给子进程,否则子进程和父进程共享资源。(也就是拷贝之前相当与线程!)
6. 参考资料
6.1 《深入理解计算机系统》
6.2 《计算机操作系统(第四版)》
6.3 《linux就是这个范》