⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 00000006.htm

📁 一份很好的linux入门资料
💻 HTM
📖 第 1 页 / 共 2 页
字号:
&nbsp;<BR>5.3&nbsp;&nbsp;套接口&nbsp;<BR>&nbsp;<BR>5.3.1&nbsp;&nbsp;系统V&nbsp;IPC机制&nbsp;<BR>&nbsp;<BR>Linux支持Unix系统V(1983)版本中的三种进程间通讯机制。它们是消息队列、&nbsp;<BR>信号灯以及共享内存。这些系统V&nbsp;IPC机制使用共同的授权方法。只有通过系统&nbsp;<BR>调用将标志符传递给核心之后,进程才能存取这些资源。这些系统V&nbsp;IPC对象使&nbsp;<BR>用与文件系统非常类似的访问控制方式。对象的引用标志符被用来作为资源表&nbsp;<BR>中的索引。这个索引值需要一些处理后才能得到。&nbsp;<BR>&nbsp;<BR>系统中所有系统V&nbsp;<BR>IPC对象的Linux数据结构包含一个ipc_perm结构,它含有进程拥有者和创建者及&nbsp;<BR>组标志符。另外还有对此对象(拥有者,组及其它)的存取模式以及IPC对象键。&nbsp;<BR>此键值被用来定位系统V&nbsp;IPC对象的引用标志符。这样的键值一共有两组:公有&nbsp;<BR>与私有。如果此键为公有,则系统中任何接受权限检查的进程都可以找到系统V&nbsp;<BR>IPC对象的引用标志符。系统V&nbsp;IPC对象绝不能用一个键值来引用,而只能使用&nbsp;<BR>引用标志符。&nbsp;<BR>&nbsp;<BR>5.3.2&nbsp;&nbsp;消息队列&nbsp;<BR>&nbsp;<BR>消息队列允许一个或者多个进程向它写入与读取消息。Linux维护着一个msgque&nbsp;<BR>消息队列链表,其中每个元素指向一个描叙消息队列的msqid_ds结构。当创建新&nbsp;<BR>的消息队列时,系统将从系统内存中分配一个msqid_ds结构,同时将其插入到数&nbsp;<BR>组中。&nbsp;<BR>&nbsp;<BR>每个msqid_ds结构包含一个ipc_perm结构和指向已经进入此队列消息的指针。另&nbsp;<BR>外,Linux保留有关队列修改时间信息,如上次系统向队列中写入的时间等。&nbsp;<BR>msqid_ds包含两个等待队列:一个为队列写入进程使用而另一个由队列读取进程&nbsp;<BR>使用。&nbsp;<BR>&nbsp;<BR>每次进程试图向写入队列写入消息时,系统将把其有效用户和组标志符与此队列&nbsp;<BR>的ipc_perm结构中的模式进行比较。如果允许写入操作,则把此消息从此进程的&nbsp;<BR>地址空间拷贝到msg数据结构中,并放置到此消息队列尾部。由于Linux严格限制&nbsp;<BR>可写入消息的个数和长度,队列中可能容纳不下这个消息。此时,此写入进程将&nbsp;<BR>被添加到这个消息队列的等待队列中,同时调用调度管理器选择新进程运行。当&nbsp;<BR>由消息从此队列中释放时,该进程将被唤醒。&nbsp;<BR>&nbsp;<BR>从队列中读的过程与之类似。进程对这个写入队列的访问权限将被再次检验。读&nbsp;<BR>取进程将选择队列中第一个消息(不管是什么类型)或者第一个某特定类型的消&nbsp;<BR>息。如果没有消息可以满足此要求,读取进程将被添加到消息队列的读取等待队&nbsp;<BR>列中,然后系统运行调度管理器。当有新消息写入队列时,进程将被唤醒继续执&nbsp;<BR>行。&nbsp;<BR>&nbsp;<BR>5.3.3&nbsp;&nbsp;信号灯&nbsp;<BR>&nbsp;<BR>信号灯最简单的形式是某个可以被多个进程检验和设置(test&amp;set)的内存单元。&nbsp;<BR>这个检验与设置操作对每个进程而言是不可中断或者说是一个原子性操作;一旦&nbsp;<BR>启动谁也终止不了。检验与设置操作的结果是信号灯当前值加1,这个值可以是正&nbsp;<BR>数也可以是负数。根据这个操作的结果,进程可能可以一直睡眠到此信号灯的值&nbsp;<BR>被另一个进程更改为止。信号灯可用来实现临界区(critical&nbsp;region):某一时&nbsp;<BR>刻在此区域内的代码只能被一个进程执行。&nbsp;<BR>&nbsp;<BR>如果你有多个协作进程从一个数据文件中读取与写入记录。有时你可能需要这些&nbsp;<BR>文件访问遵循严格的访问次序。&nbsp;<BR>那么可在文件操作代码上使用一个初始值为1的信号灯,它带有两个信号灯操作,&nbsp;<BR>一个检验并对信号灯值减1,而另一个检验并加1。第一个访问文件的进程将试图&nbsp;<BR>将信号灯值减1,如果获得成功则信号灯值变成了0。此进程于是开始使用这个数&nbsp;<BR>据文件,但是此时如果另一进程也想将信号灯值减1,则信号灯值将为-1,这次操&nbsp;<BR>作将会失败。它将挂起执行直到第一个进程完成对此数据文件的使用。此时这个&nbsp;<BR>等待进程将被唤醒,这次它对信号灯的操作将成功。&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>每个系统V&nbsp;IPC信号灯对象对应一个信号灯数组,Linux使用semid_ds结构来表示。&nbsp;<BR>系统中所有semid_ds结构由一组semary指针来指示。在每个信号灯数组中有一个&nbsp;<BR>sem_nsems,它表示一个由sem_base指向的sem结构。授权的进程可以使用系统调用&nbsp;<BR>来操纵这些包含系统V&nbsp;IPC信号灯对象的信号灯数组。这个系统调用可以定义许&nbsp;<BR>多种操作,每个操作用三个输入来描叙:信号灯索引、操作值和一组标志。信号&nbsp;<BR>灯索引是一个信号灯数组的索引,而操作值是将被加到信号灯上的数值。首先Linux&nbsp;<BR>将检查是否所有操作已经成功。如果操作值与信号灯当前数值相加大于0,或者操&nbsp;<BR>作值与信号灯当前值都是0,操作将会成功。如果所有信号灯操作失败,Linux仅仅&nbsp;<BR>会把那些操作标志没有要求系统调用为非阻塞类型的进程挂起。进程挂起后,Linux&nbsp;<BR>必须保存信号灯操作的执行状态并将当前进程放入等待队列。系统还在堆栈上建立&nbsp;<BR>sem_queue结构并填充各个域。这个sem_queue结构将被放到此信号灯对象等待队列&nbsp;<BR>的尾部(使用sem_pending和sem_pending_last指针)。系统把当前进程置入&nbsp;<BR>sem_queue结构中的等待队列(sleeper)中,然后启动调度管理器选择其它进程运行。&nbsp;<BR>&nbsp;<BR>如果所有这些信号灯操作都成功则无需挂起当前进程,Linux将对信号灯数组中的&nbsp;<BR>其他成员进行相同操作,然后检查那些处于等待或者挂起状态的进程。首先,Linux&nbsp;<BR>将依次检查挂起队列(sem_pending)中的每个成员,看信号灯操作能否继续。如果&nbsp;<BR>可以则将其sem_queue结构从挂起链表中删除并对信号灯数组发出信号灯操作。Linux&nbsp;<BR>还将唤醒处于睡眠状态的进程并使之成为下一个运行的进程。如果在对挂起队列的&nbsp;<BR>遍历过程中有的信号灯操作不能完成则Linux将一直重复此过程,直到所有信号灯操&nbsp;<BR>作完成且没有进程需要继续睡眠。&nbsp;<BR>&nbsp;<BR>但是信号灯的使用可能产生一个严重的问题:死锁。当一个进程进入临界区时它改&nbsp;<BR>变了信号灯的值而离开临界区时由于运行失败或者被kill而没有改回信号灯时,死&nbsp;<BR>锁将会发生。Linux通过维护一组描叙信号灯数组变化的链表来防止该现象的发生。&nbsp;<BR>它的具体做法是让Linux将把此信号灯设置为进程对其进行操作前的状态。这些状态&nbsp;<BR>值被保存在使用该信号灯数组进程的semid_ds和task_struct结构的sem_undo结构中。&nbsp;<BR>&nbsp;<BR>信号灯操作将迫使系统对它引起的状态变化进行维护。Linux为每个进程维护至少一&nbsp;<BR>个对应于信号灯数组的sem_undo结构。如果请求进行信号灯操作的进程没有该结构,&nbsp;<BR>则必要时Linux会为其创建一个。这个sem_undo结构将同时放入此进程的task_struct&nbsp;<BR>结构和此信号灯数组的semid_ds结构中。当对信号灯进行操作时,信号灯变化值的&nbsp;<BR>负数被置入进程的sem_undo结构中该信号的入口中。所以当操作值为2时,则此信号&nbsp;<BR>灯的调整入口中将加入一个-2。&nbsp;<BR>&nbsp;<BR>象正常退出一样,当进程被删除时,Linux将遍历该进程的sem_undo集合对信号灯数&nbsp;<BR>组使用调整值。如果信号灯集合被删除而sem_undo数据结构还在进程的task_struct&nbsp;<BR>结构中则此信号灯数组标志符将被置为无效。此时信号灯清除代码只需丢弃sem_undo&nbsp;<BR>结构即可。&nbsp;<BR>&nbsp;<BR>5.3.4&nbsp;&nbsp;共享内存&nbsp;<BR>&nbsp;<BR>共享内存允许一个或多个进程通过同时出现在它们虚拟地址空间中的内存来通讯。此&nbsp;<BR>虚拟内存的页面出现在每个共享进程页表中。但此页面并不一定位于所有共享进程虚&nbsp;<BR>拟内存的相同位置。和其它系统V&nbsp;IPC对象的使用方法一样,对共享内存区域的访问&nbsp;<BR>是通过键和访问权限检验来控制的。一旦内存被共享,则再不会检验进程对对象的使&nbsp;<BR>用方式。它依赖于其它机制,如系统V信号灯,来同步对共享内存的访问。&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>每个新创建的共享内存区域由一个shmid_ds数据结构来表示。它们被保存再shm_segs数&nbsp;<BR>组中。shmid_ds数据结构描叙共享内存的大小,进程如何使用以及共享内存映射到其&nbsp;<BR>各自地址空间的方式。由共享内存创建者控制对此内存的存取权限以及其键是公有还&nbsp;<BR>是私有。如果它由足够权限,它还可以将此共享内存加载到物理内存中。&nbsp;<BR>&nbsp;<BR>每个使用此共享内存的进程必须通过系统调用将其连接到虚拟内存上。这时进程创建&nbsp;<BR>新的vm_area_struct来描叙此共享内存。进程可以决定此共享内存在其虚拟地址空间&nbsp;<BR>的位置,或者让Linux选择一块足够大的区域。&nbsp;<BR>新的vm_area_struct结构将被放到由shmid_ds指向的vm_area_struct链表中。通过&nbsp;<BR>vm_next_shared和vm_prev_shared指针将它们连接起来。虚拟内存在连接时并没有&nbsp;<BR>创建;进程访问它时才创建。&nbsp;<BR>&nbsp;<BR>当进程首次访问共享虚拟内存中的页面时将产生页面错。当取回此页面后,Linux找&nbsp;<BR>到了描叙此页面的vm_area_struct数据结构。它包含指向使用此种类型虚拟内存的处&nbsp;<BR>理函数地址指针。共享内存页面错误处理代码将在此shmid_ds对应的页表入口链表中&nbsp;<BR>寻找是否存在此共享虚拟内存页面。如果不存在,则它将分配物理页面并为其创建页&nbsp;<BR>表入口。同时还将它放入当前进程的页表中,此入口被保存在shmid_ds结构中。这意&nbsp;<BR>味着下个试图访问此内存的进程还会产生页面错误,共享内存错误处理函数将为此进&nbsp;<BR>程使用其新创建的物理页面。这样,第一个访问虚拟内存页面的进程创建这块内存,&nbsp;<BR>随后的进程把此页面加入到各自的虚拟地址空间中。&nbsp;<BR>&nbsp;<BR>当进程不再共享此虚拟内存时,进程和共享内存的连接将被断开。如果其它进程还在&nbsp;<BR>使用这个内存,则此操作只影响当前进程。其对应的vm_area_struct结构将从shmid_ds&nbsp;<BR>结构中删除并回收。当前进程对应此共享内存地址的页表入口也将被更新并置为无效。&nbsp;<BR>当最后一个进程断开与共享内存的连接时,当前位于物理内存中的共享内存页面将被释&nbsp;<BR>放,同时还有此共享内存的shmid_ds结构。&nbsp;<BR>&nbsp;<BR>当共享内存没有被锁入物理内存时,情况将更加复杂。此时共享内存页面可能会在内存&nbsp;<BR>使用高峰期,被交换到系统的交换磁盘上。共享内存如何被交换与调入物理内存将在mm&nbsp;<BR>一章中详细描叙。&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>--&nbsp;<BR>※&nbsp;来源:·BBS&nbsp;水木清华站&nbsp;bbs.net.tsinghua.edu.cn·[FROM:&nbsp;202.114.2.2]&nbsp;<BR><CENTER><H1>BBS水木清华站∶精华区</H1></CENTER></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -