进程(process)和线程(thread)是操作系统的基本概念,可以将两者理解为CPU时间段的描述。由于CPU的速度远高于内存和硬盘等读写速度,为了提高CPU的执行效率,减少因为程序等待带来的CPU空转以及其他计算机软硬件资源的浪费,引入了进程和线程。
并行和并发
并行(concurrency)指物理上同时执行。
并发(parallesim)指能够让多个任务在逻辑上交织执行的程序设计,不一定要同一时刻发生。
进程
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.
- 进程就是包括上下文切换的程序执行时间总和 = CPU加载上下文+CPU执行+CPU保存上下文
- 进程是为了提高CPU的执行效率,减少因为程序等待带来的CPU空转以及其他计算机软硬件资源的浪费而提出来的。
程序和进程有什么区别?
进程是程序在计算机上的一次执行活动。当你运行一个程序,你就启动了一个进程。显然,程序只是一组指令的有序集合,它本身没有任何运行的含义,只是一个静态实体。而进程则不同,它是程序在某个数据集上的执行,是一个动态实体。
线程
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。
-
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。
-
优点:
- 在进程内创建、终止线程比创建、终止进程要快;
- 同一进程内的线程间切换比进程间的切换要快,尤其是用户级线程间的切换。
-
总线程数<= CPU数量:并行运行
总线程数> CPU数量:并发运行
进程和线程的联系
- 线程是进程的一部分,是属于进程的。
- 线程运行在进程空间内,同一进程所产生的线程共享同一内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除。线程可与属于同一进程的其它线程共享进程所拥有的全部资源,但是其本身基本上不拥有系统资源,只拥有一点在运行中必不可少的信息(如程序计数器、一组寄存器和栈)。
- 一个没有线程的进程是可以被看作单线程的。
进程和线程的区别
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。
- 系统在运行的时候会为每个进程分配不同的内存区域,但是不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只能共享资源。那就是说,出了CPU之外(线程在运行的时候要占用CPU资源),计算机内部的软硬件资源的分配与线程无关,线程只能共享它所属进程的资源。
- 进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程没有单独的地址空间,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈)。
- 一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,
- 与进程的控制表PCB相似,线程也有自己的控制表TCB,但是TCB中所保存的线程状态比PCB表中少多了。因此进程在切换时,耗费资源较大,效率要差一些。
- 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。因此对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
通信
进程间通信
进程间通信(IPC,Inter-Process Communication)指至少两个进程或线程间传送数据或信号的一些技术或方法。
主要的 IPC 方法
套接口(Socket)
更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字。
管道(Pipe)
限制:一是半双工的通信,数据只能单向流动,二是只能在具有亲缘关系的进程间使用。
- 进程的亲缘关系通常是指父子进程关系。
- 流管道s_pipe: 去除了第一种限制,可以双向传输。
- 缺点:速度慢,容量有限,只有父子进程能通讯。
命名管道(named pipe) FIFO
命名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。
- 缺点:任何进程间都能通讯,但速度慢
消息队列(Message Queue)
消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
- 容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题。
信号(Signal)
信号用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身。
- 主要作为进程间以及同一进程不同线程之间的同步手段。
信号量(semaphore)
信号量是一个计数器,可以用来控制多个进程对共享资源的访问。
- 主要作为进程间以及同一进程内不同线程之间的同步手段。
- 缺点:不能传递复杂消息,只能用来同步。
共享内存( shared memory )
共享内存就是映射一段能被其他进程所访问的内存。
- 这段共享内存由一个进程创建,但多个进程都可以访问。
- 共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。
- 共享内存并未提供同步机制,因此往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。
- 能够很容易控制容量,速度快,但要保持同步。
- 可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了同一进程内的一块内存。
线程间通信方式
- 使用全局变量 主要由于多个线程可能更改全局变量,因此全局变量最好声明为violate。
- 使用消息实现通信
- 使用事件CEvent类实现线程间通信
线程间同步方式
各个线程可以访问进程中的公共变量,资源,所以使用多线程的过程中需要注意的问题是如何防止两个或两个以上的线程同时访问同一个数据,以免破坏数据的完整性。
- 数据之间的相互制约包括
- 直接制约关系,即一个线程的处理结果,为另一个线程的输入,因此线程之间直接制约着,这种关系可以称之为同步关系
- 间接制约关系,即两个线程需要访问同一资源,该资源在同一时刻只能被一个线程访问,这种关系称之为线程间对资源的互斥访问,某种意义上说互斥是一种制约关系更小的同步
临界区
临界区对应着一个CcriticalSection对象,当线程需要访问保护数据时,调用EnterCriticalSection函数;当对保护数据的操作完成之后,调用LeaveCriticalSection函数释放对临界区对象的拥有权,以使另一个线程可以夺取临界区对象并访问受保护的数据。
互斥量
互斥与临界区很相似,但是使用时相对复杂一些(互斥量为内核对象),不仅可以在同一应用程序的线程间实现同步,还可以在不同的进程间实现同步,从而实现资源的安全共享。
- 由于互斥量为内核对象,因此还可以进行进程间通信,且不会出现“遗弃”问题。
信号量
信号量的用法和互斥的用法很相似,不同的是它可以同一时刻允许多个线程访问同一个资源。
- 信号量也属于内核对象,因此还可以进行进程间通信。