-
进程与线程
-
进程与线程概述
进程:
一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间比如在Windows系统中,一个运行的xx.exe就是一个进程。线程:
线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。进程是资源分配的单位,资源分配给进程,同一进程的所有线程共享该进程的所有资源。
线程是资源调度的单位,处理机分给线程,即真正在处理机上运行的是线程。
-
进程与线程区别
根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位;
资源开销:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。
包含关系:如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
内存分配:线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的。进程中的堆和全局变量区是线程之间共享的,存放申请的资源、全局变量、静态变量等;而栈是线程私有的,局部变量等存储在此。
影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。
执行过程:每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行。
-
-
进程间通信方式—IPC(Inter-Process Communication)
-
linux下进程间通信主要有以下几种方法。
-
管道(PIPE)
-
管道是一种半双工的通信方式,有固定的读端和写端。是UNIX最古老的IPC形式。
-
无名管道只能在具有亲缘关系的进程间使用,而有名管道允许无亲缘关系进程间的通信。
-
优点:方便使用
-
缺点:半双工只能单向使用、速度慢,容量有限,只能传输字节流。无名管道不能在无亲缘进程间使用。
-
-
消息队列
- 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息有特定的格式。
- 消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
- 优点:可以实现任意进程间的通信,并通过系统调用函数来实现消息发送和接收之间的同步,无需考虑同步问题,方便。
- 缺点:信息的复制(需要从队列中拷贝到内存中)需要额外消耗 CPU 的时间,不适宜于信息量大或操作频繁的场合。
-
共享内存
- 共享内存这个通信方式就可以很好着解决拷贝所消耗的时间了。我们可以让两个进程各自拿出一块虚拟地址空间来,然后映射到相同的物理内存中,这样,两个进程虽然有着独立的虚拟内存空间,但有一部分却是映射到相同的物理内存,这就完成了内存共享机制了。
- 共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。
- 优点:无须复制,快捷,信息量大
- 缺点:
- 通信是通过将共享空间缓冲区直接附加到进程的虚拟地址空间中来实现的,因此会带来进程间的读写操作的同步问题。
- 利用内存缓冲区直接交换信息,内存的实体存在于计算机中,只能同一个计算机系统中的诸多进程共享,不方便在不同计算机中的分布式网络通信。
-
信号量
- 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制。(比如共享内存中的同步问题就可以用信号量来解决)
- 信号量用于进程间同步,大量的数据传输则不适合,若要在进程间传递数据需要结合共享内存。
- 信号量基于操作系统的 P、V原子操作。
-
信号
- 信号与信号量不同,信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。主要是是一种进程间处理异步事件的方式。
- 信号由软中断来提供服务,在进程间传递一些事件,比如杀死进程等。
-
套接字socket
- 套接字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。采用C/S 服务器客户端模型。
- 优点:
传输数据为字节级,传输数据可自定义,数据量小效率高;
传输数据时间短,性能高;
适合于客户端和服务器端之间信息实时交互;
可以加密,数据安全性强; - 缺点:需对传输的数据进行解析,转化成应用级的数据。
-
-
线程间通信方式
- 线程间的通信目的主要是用于线程同步,所以线程没有像进程通信中的用于数据交换的通信机制。线程之间共享一些空间,数据交换可以用全局变量等方式,要注意同步。
- 锁机制:包括互斥锁、条件变量、读写锁
- 互斥锁提供了以排他方式防止数据结构被并发修改的方法。
- 读写锁允许多个线程同时读共享数据,而对写操作是互斥的。
- 条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。
- 信号量机制(Semaphore):包括无名线程信号量和命名线程信号量
- 信号机制(Signal):类似进程间的信号处理
对比维度 | 多进程 | 多线程 | 总结 |
---|---|---|---|
数据共享、同步 | 数据共享复杂,需要用IPC;但同步简单由于数据是分开的 | 因为共享进程数据,数据共享简单,但也是因为这个原因导致同步复杂 | 各有优势 |
内存、CPU | 占用内存多,切换复杂,CPU利用率低 | 占用内存少,切换简单,CPU利用率高 | 线程占优 |
创建销毁、切换 | 创建、销毁、切换复杂,速度慢 | 创建、销毁、切换简单,速度很快 | 线程占优 |
编程、调试 | 编程简单,调试简单 | 编程复杂,调试复杂 | 进程占优 |
可靠性 | 进程间不会互相影响 | 一个线程挂掉将导致整个进程挂掉 | 进程占优 |
分布式 | 适应于多核、多机分布式;如果一台机器不够,扩展到多台机器比较简单 | 适应于多核分布式 | 进程占优 |
-
多进程和多线程的适用场景
- 需要频繁创建销毁:多线程适合。例如web服务器,来一个连接就建立一个线程,创建销毁的成本低。
- 大量计算:优先使用多线程。大量计算,当然就是要耗费很多CPU,切换频繁了,这种情况下线程是最合适的。这种原则最常见的是图像处理、算法处理。
- 各任务之间强相关、弱相关:强相关优先使用线程,弱相关使用进程。强相关在任务之间肯定有合作密切,切换频繁。
- 多机分布的用进程,多核分布的用线程。