进程同步的方式有哪些?
临界区
临界区是一段代码,在临界区内进程将访问临界资源。任何时候最多只有一个进程可以进入临界区,也就是说,临界区具有排他性。所以,为了互斥访问临界资源,每个进程在进入临界区之前,需要先进行检查。
互斥量
就是使用一个互斥的变量来直接制约多个进程,每个进程只有拥有这个变量才具有访问公共资源的权限,因为互斥量只有一个,所以能保证资源的正确访问。
信号量
信号量(Semaphore)是一个整型变量,可以对其执行自增和自减操作,自减操作通常也叫做P操作,自增操作也称为V操作。这两个操作需要被设计成原语,是不可分割,通常的做法是在执行这些操作的时候屏蔽中断。进程使用这两个操作进行同步。
对于P操作,如果执行操作后信号量小于 0,那么执行该操作的进程就会阻塞,否则继续执行;
对于V操作,如果操作之后的信号量小于等于0,那么就会从阻塞队列唤醒一个进程。
管程
管程使用的是面向对象思想,将表示共享资源的数据结构还有相关的操作,包括同步机制,都集中并封装到一起。所有进程都只能通过管程间接访问临界资源,而管程只允许一个进程进入并执行操作,从而实现进程互斥。管程中设置了多个条件变量,表示多个进程被阻塞或挂起的条件。对条件变量执行 wait() 操作会导致调用进程阻塞,把管程让出来给另一个进程持有。signal() 操作用于唤醒被阻塞的进程。管程有一个重要特性,就是在一个时刻只能有一个进程使用管程。进程在无法继续执行的时候不能一直占用管程,否则其它进程永远不能使用管程。
进程间通信的方式有哪些?
管道
管道是半双工的,数据只能向一个方向流动;如果需要双方通信时,需要建立起两个管道。
管道只能用于父子进程或者兄弟进程之间或者说具有亲缘关系的进程;
管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,只存在与内存中。
管道的实质是一个内核缓冲区,进程以先进先出的方式从缓冲区存取数据,管道一端的进程顺序的将数据写入缓冲区,另一端的进程则顺序的读出数据。该缓冲区可以看做是一个循环队列,读和写的位置都是自动增长的,不能随意改变,一个数据只能被读一次,读出来以后在缓冲区就不复存在了。当缓冲区读空或者写满时,有一定的规则控制相应的读进程或者写进程进入等待队列,当空的缓冲区有新数据写入或者满的缓冲区有数据读出来时,就唤醒等待队列中的进程继续读写。
管道的主要局限性正体现在它的特点上,比如只支持单向数据流,只能用于具有亲缘关系的进程之间,没有名字,管道的缓冲区是有限的等等。
命名管道
这种管道也叫FIFO。命名管道不同于管道的地方,在于它提供了一个路径名与之关联,以命名管道的文件形式存在于文件系统中,这样,即使与命名管道的创建进程不存在亲缘关系的进程,只要可以访问文件系统中的这个路径,就能够彼此通过命名管道相互通信。命名管道严格遵循先进先出原则的,不支持诸如数据随机定位。命名管道的名字存在于文件系统中,但内容存放在内存中。
消息队列
消息队列是消息的链表,具有特定的格式,它是存放在内存里面的,并且每个消息队列都有唯一的标识。消息队列允许一个或多个进程向它写入与读取消息,所以,利用消息队列,一个进程可以将一个数据块发送到另一个进程,每个数据块都有一个类型,接收进程可以独立地接收含有不同类型的数据结构,这个过程是异步的,我们可以通过发送消息来避免命名管道的同步和阻塞问题。但消息队列的数据块有一个最大长度的大小限制。