进程与线程
定义
进程
一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程;一个进程由这些部分组成:PC;寄存器;stack;heap;data section;
线程
CPU调度的最小单元。一个线程包括:thread ID;PC;寄存器集;stack。
区别
- 进程具有独立的地址空间,而同一个进程下的线程则共享进程的地址空间;由于建立进程时,需要分配数据块,栈块和代码块等来维护这个进程,而线程则共享大部分数据,甚至可以访问进程的每一块内存,所以进程的创立和切换都是比较昂贵的工作模式,而线程则相对轻量;
- 线程的通信会更加方便,这也是建立在线程共享大部分数据的基础上。而且,一个线程建立的heap能被同一进程下的其它线程访问;
- 多进程比多线程健壮,大多数情况下,一个线程挂了整个进程都会挂了,而进程则是独立的。
- 多线程与多进程:多进程需要开辟更多的独立空间,消耗大量的资源;多线程则是共享数据,轻量级并发。对于需要频繁交互数据,或者是高并发的情况下,用多线程;而不需要频繁交互数据的并发编程则用多进程。
进程
进程状态
进程有五种状态:new、ready、running、waiting、terminate。
状态变化如下:
组成进程的部分
- program code、data
- PCB:stack、os的资源、registers
PCB
进程控制块:每个进程都信息相关:
- process state;
- program counter;
- CPU registers;
- CPU scheduling info;
- memory-management info;
- accounting info;
- file management;
- IO status info;
在linux里,在头文件sched.h中的task_struct存着进程的有关信息。
pid
以unix为例,fork()之后,父进程与子进程具有相同上下文。
在子进程中,fork()返回值为0;在父进程中,pid()返回值为子进程的pid号。
进程间通信
通信机制:
- 信号量:用来实现进程间的同步与互斥,但不能存储通信数据;
- 消息队列:由链表,存放在内核中并由消息队列标识符标识。
- 共享内存:能实现内存被多个进程共享;
- 管道(pipe):半双工的通信方式,单向通信,而且只能在具有亲缘关系的进程间通信;
- 命名管道:同样半双工,但允许非亲缘关系的进程通信;
- 信号:通知某个进程事件的发生;
- 套接字;
线程
user与kernel 线程
user 线程:
用户线程由应用进程进行维护;
内核不知道用户线程的存在;
用户线程的切换不需要内核特权;
如果用户现场发起系统调用而阻塞了,则整个进程都在等待;
kernel 线程:
内核维护进程和线程的上下文;
线程的切换由内核完成;
时间片会由CPU分配给线程,因此多线程的进程会获得更多的CPU时间;
一个线程阻塞,不会影响其他线程的运行;
- 比较:
- 用户线程由于不用陷入内核,所以切换速度更快;
- 用户线程允许用户进程自定义调度算法;
- 用户线程跨平台会更容易;
- 用户线程难以解决阻塞的问题;
- 用户线程由于没有时钟,难以调度;
linux下的使用
四个常用函数:pthread_create; pthread_join; pthread_self; pthread_exit;
同步与互斥
- 互斥是指在同一时间只允许一个访问者进行访问,具有唯一性和排他性;
- 同步是指在实现互斥的基础上,通过某些机制实现访问者对资源的有序访问;