全部博文(436)
分类: LINUX
2013-02-26 18:58:35
红色标记为重点
1、管道和命名管道(FIFO):最适合在进程之间实现生产者/消费者的交互进程向管道中写入/读出数据。
2、消息(小块数据):进程在预定义的消息队列
3、共享内存区:允许进程通过共享内存块来交换信息,在必须共享大量数据的应用中,这可能是高级的进程通信形式。
4、套接字:允许不同计算机上的进程通过网络交换数据
5、系统调用(详见第十章系统调用):指运行在使用者空间的程序向操作系统内核请求需要更高权限运行的服务。
6、POSIX:可移植性操作系统接口。
7、半双工(half-duplex)的系统允许二台设备之间的双向资料传输,但不能同时进行。因此同一时间只允许一设备传送资料,若另一设备要传送资料,需等原来传送资料的设备传送完成后再处理。类似对讲机。
本章介绍用户态的进程之间如何进程同步和交换数据。
问:什么是用户态?
答:用户态(user mode):在计算机结构指两项类似的概念。
⑴在CPU的设计中,用户态指非特权状态。在此状态下,执行的代码被硬件限定,不能进行某些操作,比如写入其他进程的存储空间,以防止给操作系统带来安全隐患。
⑵在操作系统的设计中,用户态也类似,指非特权的执行状态。内核禁止此状态下的代码进行潜在危险的操作,比如写入系统配置文件、杀掉其他用户的进程、重启系统等。
我们这里的用户态指的是操作系统中的用户态,操作系统中的用户态,指权限等级中的一般级别,与之相对的是管理员或者超级用户(类Unix系统中,名为“root”或“super user”等)的特权级别。用户态启动的每个进程,根据运行该进程的用户,都被系统赋予特定的权限。
进程通信形式:1、管道(pipe)2、管道命名(FIFO)3、IPC(Interprocess Communieation)
1、 管道:是所有Unix(操作系统)都愿意提供的一种进程间通信机制,pipe是进程之间的一个单向数据流。
2、 创建、使用管道
Pipe被看作是打开的文件,但在已安装的文件系统中没有相对应的映像。可以使用pipe()系统调用来创建一个新管道。这个系统调用返回一对文件描述符,然后进程通过fork()把这两个描述符传递给他的子进程。
POSIX[6]只定义了半双工[7]的管道,因此即使pipe()系统调用返回两个描述符,在使用一个文件描述符之前得把另一个文件描述符关闭。
问:什么是半双工?
答:半双工(half-duplex)的系统允许二台设备之间的双向资料传输,但不能同时进行。因此同一时间只允许一设备传送资料,若另一设备要传送资料,需等原来传送资料的设备传送完成后再处理。类似对讲机。
除pipe()系统调用外,Unix提供了popen()和pclose()的封装函数。用popen()函数创建管道之后就可以使用C函数库中的高级I/O函数对这个管道操作。
4、管道的数据结构
对于每个管道来说,内核都要创建一个索引节点对象和两个文件对象,一个文件对象用于读,另外一个对象用于写。当索引节点指的是管道时,其i_pipe字段指向一个如下表所示的结构。
问:索引节点是什么?
答:Linux文件系统使用索引节点来记录文件信息,作用类似于Windows下的文件分配表。索引节点是一个结构,它包含了一个文件的长度、创建及修改时间、权限、所属关系、磁盘中的位置等信息。
Pipe_inode_info数据结构的bufs(上图圈中的字段)字段存放一个具有16个pipe_buffer对象的数组,每个对象代表一个管道缓冲区。该对象的字段如下图
5、从管道读取数据
P为管道大小,n为要读取字节数
6、从管道写入数据
n为要写入数据字节数,u为未用的数据字节数
1、FIFO:是一种双向通信管道。为了突破进程无法打开已经存在的管道的缺陷,Unix引入了一种称为命名管道或者FIFO的特殊文件类型。有了磁盘索引节点,就使得任何进程都可以访问FIFO,因为FIFO文件名包含在系统的目录树中。FIFO和管道几乎是一样的,并使用相同的pipe_inode_info结构。只有两点主要差别:①FIFO索引节点出现在系统目录树上而不是pipefs特殊文件系统中;②FIFO是一种双向通信管道。FIFO一旦被创建,就可以使用普通的open(),read(),write(),close()系统调用访问FIFO
2、创建、打开FIFO
进程通过执行mkbod()系统调用创建一个FIFO,其中参数是新FIFO的路径名以及与S_IFIFO(0*10000)与这个新文件的权限位掩码进行逻辑或的结果
1、IPC(Interprocess Communieation):是①通过信号量与其他进程进行同步②向其他进程发送消息或者从其他进程接收消息③和其他进程共享一段内存区 的进程间通信方式。特殊点:IPC资源可以由任一进程使用,包括不是父子关系的进程。
2、使用IPC资源
根据新资源是信号量、消息队列还是共享内存区,分别调用semget()、msgget()或者shmget()函数创建IPC资源。
三个函数的主要目的都是从IPC关键字中导出相应的IPC标示符,进程以后就可以使用这个标示符对资源进行访问。
假设两个独立的进程共享一个公共的IPC资源。可以使用两种方法:①两个进程统一使用固定的、预定义的IPC关键字。②一个进程通过指定IPC_PRIVATE作为自己的IPC关键字来调用semget()、msgget()、或shmget()函数。一个新的IPC资源被分配,这个进程或者可以与另一进程共享IPC标示符,或者创建另一个进程。
每个IPC标示符都是通过结合使用与资源类型相关的位置使用序号(slot usage sequence number)记为s、已分配资源的任意位置索引(slot index)记为i以及内核中可分配资源所选定的最大值记为M而计算出来的。
IPC标示符=s*M+i
1、 Ipc()系统调用
所有IPC函数都必须通过适当的Linux系统调用实现。
2、 IPC信号量
IPC信号量是计数器,用来为多个进程共享的数据结构提供受控访问。如果受保护的资源是可用的,信号量的值为正;反之则为0。
IPC信号量数据结构:
(1)、可取消的信号量操作
一个进程突然放弃执行,不可以取消已开始执行的操作,但通过把这些操作定义成可取消的,进程就可以让内核把信号量返回到一致状态并允许其他进程继续执行。进程可以在semop()函数中指定SEM_UNDO标志来请求可取消的操作。
(2)、挂起请求的队列
内核给每个IPC信号量都分配了一个挂起请求队列,用来标识正在等待数组中的一个或多个信号量的进程。这个队列是一个sem_queue数据结构的双向链表。
1、 IPC消息
进程彼此之间可以通过IPC消息进行通信。进程产生的每条消息都被发送到一个IPC消息队列中,这个消息一直存放在队列中直到另一个进程将其读走为止。
为了发送一条消息,进程要调用msgsnd()函数
进程要获得一条消息就要调用msgrcv()函数
1、 IPC共享内存
这种机制允许两个或多个进程通过把公共数据结构放入一个共享内存区(IPC shared memory region)来访问它们。
(1)、换出IPC共享内存区的页
因为IPC共享内存区映射的是磁盘上没有映像的特殊索引节点,因此其页是可交换的。
(2)、IPC共享内存区的请求调页
IPC共享内存区的页可以被换出,通过shmat()加入进程的页都是哑元页,但是它不修改进程的也表,因此可以通过请求调页机制来处理这些页。
POSIX标准(IEEE Std 1003.1-2001)基于消息列队定义了一个IPC机制,就是POSIX消息队列。
POSIX消息队列通过一套库函数来实现