进程和线程有什么区别和关系,以及进程间通信的方式,这几乎是C++笔试面试必须要问的一个问题,终于静下心来好好看了看相关的书和相关的百度。整理了一份自认为还比较好理解的文档。
进程和线程的区别:
一个程序就是一个进程,而一个程序中的多个任务则被称为线程。进程是表示资源分配的基本单位,又是调度运行的基本单位。线程是进程中执行运算的最小单位,亦即执行处理机调度的基本单位。
(1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。线程是操作系统可识别的最小执行和调度单位。
(2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。同一进程中的多个线程共享代码段(代码和常量),数据段(全局变量和静态变量),扩展段(堆存储)。但是每个线程拥有自己的栈段,栈段又叫运行时段,用来存放所有局部变量和临时变量。
(3)处理机分给线程,即真正在处理机上运行的是线程。
(4)线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。
如果把上课的过程比作进程,那么每个学生就是一个线程,他们共享教室,即线程共享进程的内存空间。每一个时刻,只能一个学生问老师问题,老师回答完毕,轮到下一个。即线程在一个时间片内占有cpu。
简而言之,线程就是把一个进程分为很多片,每一片都可以是一个独立的流程。这已经明显不同于多进程了,进程是一个拷贝的流程,而线程只是把一条河流截成很多条小溪。它没有拷贝这些额外的开销,但是仅仅是现存的一条河流,就被多线程技术几乎无开销地转成很多条小流程,它的伟大就在于它少之又少的系统开销。
线程通信
线程之间可以通过共享的全局变量进行通信。
线程的主要优点在于协同线程之间的数据共享(通过全局变量)更为容易,就某些算法来说,以多线程实现比多进程实现更加自然。
进程通信
每个进程都有一个唯一的进程标识号(process ID),并保存有对其父进程号的记录。
进程的虚拟内存逻辑上被划分为许多段:文本段,数据段,栈和堆
栈由一系列帧组成,随函数调用而增加,随函数返回而减。每个帧都包含有函数局部变量,函数实参以及单个函数调用的调用链接信息。
用于进程间通讯(IPC)的四种不同技术:
1.消息传递(管道,FIFO,posix和system v消息队列)
2.同步(互斥锁,条件变量,读写锁,文件和记录锁,Posix和System V信号灯)
3.共享内存区(匿名共享内存区,有名Posix共享内存区,有名System V共享内存区)
4.过程调用(Solaris门,Sun RPC)
消息队列和过程调用往往单独使用,也就是说它们通常提供了自己的同步机制.相反,共享内存区通常需要由应用程序提供的某种同步形式才能正常工作.解决某个特定问题应使用哪种IPC不存在简单的判定,应该逐渐熟悉各种IPC形式提供的机制,然后根据特定应用的要求比较它们的特性.
通信工具包括管道,命名管道FIFO,套接字socket,消息队列以及共享内存。
同步工具包括信号量和文件锁
管道:
简单来说,可以看做是一组管道,它允许数据从一个进程流向另一个进程。一个管道是一个字节流,数据传递是单向的,一段写入,一端读取。根据先入先出的规则进行读取,没有边界。如果需要双向通信,则需要创建两个管道,但是这样存在死锁问题,不能同时读取或者同时写入。
速度慢,容量有限,只有父子进程能通讯
FIFO(也称为命名管道):
与管道类似,差别在于FIFO在文件系统中拥有一个名字,并且其打开方式与打开一个普通文件是一样的,就能够将其用于非相关进程之间的通信(如客户端和服务器)。FIFO也有一个写入端和读取端,并且从管道中读取数据的顺序与写入顺序一样。
任何进程间都能通讯,但速度慢
消息队列:
与管道类似,但是是有边界的,它能为每个消息加上一个数字类型。读取进程可以按照先入先出顺序,也可以根据类型来选择消息或者它们可以采用一种优先队列策略以便优先读取高优先级的消息。
消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
1消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
2消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
3消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
信号量:
信号量不是用来在进程间传输数据的,相反,他们用来同步进程的动作。常被用来同步一块共享内存的访问以防止出现一个进程在访问共享内存的同时,另一个更新这块内存。
信号量(semaphore)与已经介绍过的 IPC 结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。
特点:
信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。
每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。
支持信号量组。
共享内存:
使多个进程能够共享内存的同一块区域。一个进程一旦更新了共享内存,这个变更立即对共享同一个内存短的其他进程可见。
最快的一种通信方式,多个进程可同时访问同一片内存空间,相对其他方式来说具有更少的数据拷贝,效率较高。
因为多个进程可以同时操作,所以需要进行同步。需要结合信号灯或其他方式来实现多个进程间同步,自身不具备同步机制。
信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。
例子:使用了【共享内存+信号量+消息队列】的组合来实现服务器进程与客户进程间的通信。
· 共享内存用来传递数据;
· 信号量用来同步;
· 消息队列用来 在客户端修改了共享内存后 通知服务器读取。
套接字(Socket):
与其他通信机制不同的是,它可用于不同机器间的进程通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字。