正襟危坐说--操作系统(伍):进程间通信

进程(线程)间通信

-----------关于进程间通信,以后会有专门的一个专题,故在此简单介绍。

两个进程在不同的地址空间中,它们之间如何通信?1,通过main函数传入参数。传递的消息只能是文本消息(当然,你也可以把二进制消息转成文本的),传递的消息小,且不灵活。2,通过文件。这样当然可以,只是I/O操作会导致程序效率较低。

为了解决我们的问题,操作系统给我们提供了一些进程间通信的机制。我们调用这些系统调用,可安全方便地实现在进程间通信。

管道

一个线程向这片存储空间的一端写入信息,另一个线程从存储空间的另一端读取信息。此方式为管道。管道所占的空间既可以是内存,也可以是磁盘(一般是内存)。

从根本上说,管道是一个线性字节数组。可以使用文件读写的方式进行访问,但却不是文件。从文件系统看不到管道。

管道的一个重要的特点是使用管道的两个线程之间必须存在某种关系(比如是父子进程)

例:

在程序里,创建管道需要使用系统调用popen( )或pipe( )。pipe调用将返回两个文件描述符,其中一个用于从管道进行读操作,一个用于写入管道。

通常情况下,在使用pipe调用创建管道后,再使用fork产生两个进程,这两个进程使用pipe返回的文件描述符进行通信。

int  pp[2] ;
pipe(pp) ;
if (fork() == 0) //子进程
{
       read(pp[0);  //父进程读
}
else {
       write(pp[1]);  //子进程写
}

 

FIFO(记名管道)

如果两个不相关的线程(如两个不同进程里面的线程),之间进行管道通信,则需要使用记名管道

记名管道与文件系统共享一个名字空间,即我们可以从文件系统中看到记名管道。也就是说,记名管道的名字不能与文件系统里的任何文件重名。(它的名字在文件系统中而已,其并不是文件)

FIFO是一种只能在单台主机上使用的IPC形式,尽管在文件系统中有名字,它们也只能使用在本地文件系统上,而不能用在通过NFS安装的文件系统上。

注意:管道和FIFO,在某一个进程向它们写入信息之前,需要另外一个进程在该管道上等待。

 

信号量

在计算机里,信号量实际上就是一个简单的整数。一个进程在信号变为0或1的情况下推进,并且将信号变为1或0来防止别的进程推进。当进程完成任务后,则将信号再变为0或1,从而允许其他进程执行。

信号量不仅是一种通信机制,更是一种同步机制。

 

共享内存

若两个进程需要共享大量数据,则需要共享内存。共享内存就是两个进程共同拥有同一片内存。这片内存中的任何内容,二者均可以访问。

要使用共享内存进行通信,一个进程首先创建一片内存空间专门作为通信用,而其他进程则将该片内存映射到自己的(虚拟)地址空间。这样,读写自己地址空间中对应共享内存的区域时,就是在和其他进程进行通信。

注意,共享内存和管道是形似而神不似。共享内存的访问方式是随机的,而不是只能从一端写,另一端读,其灵活性大,能够传递的信息也复杂得多。

注意,使用全局变量在同一个进程的线程间实现通信不称为共享内存。

 

消息队列

消息队列是一列具有头和尾的消息队列。新来的消息放在队列尾部,而读取消息则从队列头部开始。消息队列一般是由链表实现的。

★一头读,一头写,看上去像管道,但它不是管道。首先,它无需固定的读写进程,任何进程都可以读写(当然是有权限的进程)。在某个进程往一个队列写入消息之前,并不需要另外某个进程在该队列上等待消息到达。这跟管道和FIFO是相反的。

其次,它可以同时支持多个进程,多个进程可以读写消息队列。即所谓的多对多,而不是管道的点对点。

 

 

原文地址:https://www.cnblogs.com/riasky/p/3430825.html