日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Linux進(jìn)程間通信分類(非原創(chuàng))

 風(fēng)雪夜歸人_95 2016-03-01
本文主要摘自網(wǎng)絡(luò):http://blog.csdn.net/sunmenggmail/article/details/7888746
       linux下的進(jìn)程通信手段基本上是從Unix平臺上的進(jìn)程通信手段繼承而來的。而對Unix發(fā)展做出重大貢獻(xiàn)的兩大主力AT&T的貝爾實(shí)驗(yàn)室及 BSD(加州大學(xué)伯克利分校的伯克利軟件發(fā)布中心)在進(jìn)程間通信方面的側(cè)重點(diǎn)有所不同。前者對Unix早期的進(jìn)程間通信手段進(jìn)行了系統(tǒng)的改進(jìn)和擴(kuò)充,形成 了“system V IPC”,通信進(jìn)程局限在單個(gè)計(jì)算機(jī)內(nèi);后者則跳過了該限制,形成了基于套接口(socket)的進(jìn)程間通信機(jī)制。Linux則把兩者繼承了下來,如圖 示:
 


      Unix IPC包括:管道、FIFO、信號。
      System V IPC包括:System V消息隊(duì)列、System V信號燈、System V共享內(nèi)存區(qū)。
      Posix IPC包括: Posix消息隊(duì)列、Posix信號燈、Posix共享內(nèi)存區(qū)。

      有兩點(diǎn)需要簡單說明一下:1)由于Unix版本的多樣性,電子電氣工程協(xié)會(huì)(IEEE)開發(fā)了一個(gè)獨(dú)立的Unix標(biāo)準(zhǔn),這個(gè)新的ANSI Unix標(biāo)準(zhǔn)被稱為計(jì)算機(jī)環(huán)境的可移植性操作系統(tǒng)界面(PSOIX)?,F(xiàn)有大部分Unix和流行版本都是遵循POSIX標(biāo)準(zhǔn)的,而Linux從一開始就遵 循POSIX標(biāo)準(zhǔn);2)BSD并不是沒有涉足單機(jī)內(nèi)的進(jìn)程間通信(socket本身就可以用于單機(jī)內(nèi)的進(jìn)程間通信)。事實(shí)上,很多Unix版本的單機(jī) IPC留有BSD的痕跡,如4.4BSD支持的匿名內(nèi)存映射、4.3+BSD對可靠信號語義的實(shí)現(xiàn)等等。
 

linux下進(jìn)程間通信的幾種主要手段簡介:

  1. 管道(Pipe)及有名管道(named pipe):管道可用于具有親緣關(guān)系進(jìn)程間的通信,有名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關(guān)系進(jìn)程間的通信;
  2. 信號(Signal):信號是比較復(fù)雜的通信方式,用于通知接受進(jìn)程有某種事件發(fā)生,除了用于進(jìn)程間通信外,進(jìn)程還可以發(fā)送信號給進(jìn)程本身;linux除了支持Unix早期信號語義函數(shù)sigal外,還支持語義符合Posix.1標(biāo)準(zhǔn)的信號函數(shù)sigaction(實(shí)際上,該函數(shù)是基于BSD的,BSD為了實(shí)現(xiàn)可靠信號機(jī)制,又能夠統(tǒng)一對外接口,用sigaction函數(shù)重新實(shí)現(xiàn)了signal函數(shù));
  3. 報(bào)文(Message)隊(duì)列(消息隊(duì)列):消息隊(duì)列是消息的鏈接表,包括Posix消息隊(duì)列system V消息隊(duì)列。有足夠權(quán)限的進(jìn)程可以向隊(duì)列中添加消息,被賦予讀權(quán)限的進(jìn)程則可以讀走隊(duì)列中的消息。消息隊(duì)列克服了信號承載信息量少,管道只能承載無格式字 節(jié)流以及緩沖區(qū)大小受限等缺點(diǎn)。
  4. 共享內(nèi)存:使得多個(gè)進(jìn)程可以訪問同一塊內(nèi)存空間,是最快的可用IPC形式。是針對其他通信機(jī)制運(yùn)行效率較低而設(shè)計(jì)的。往往與其它通信機(jī)制,如信號量結(jié)合使用,來達(dá)到進(jìn)程間的同步及互斥。
  5. 信號量(semaphore):主要作為進(jìn)程間以及同一進(jìn)程不同線程之間的同步手段。
  6. 套接口(Socket):更為一般的進(jìn)程間通信機(jī)制,可用于不同機(jī)器之間的進(jìn)程間通信。起初是由Unix系統(tǒng)的BSD分支開發(fā)出來的,但現(xiàn)在一般可以移植到其它類Unix系統(tǒng)上:Linux和System V的變種都支持套接字。

1、管道(pipe)

管道是進(jìn)程間通信的主要手段之一。一個(gè)管道實(shí)際上就是個(gè)只存在于內(nèi)存中的文件,對這個(gè)文件的操作要通過兩個(gè)已經(jīng)打開文件進(jìn)行,它們分別代表管道的兩端。管道是一種特殊的文件,它不屬于某一種文件系統(tǒng),而是一種獨(dú)立的文件系統(tǒng),有其自己的數(shù)據(jù)結(jié)構(gòu)。根據(jù)管道的適用范圍將其分為:無名管道和命名管道。

●     無名管道

主要用于父進(jìn)程與子進(jìn)程之間,或者兩個(gè)兄弟進(jìn)程之間。在linux系統(tǒng)中可以通過系統(tǒng)調(diào)用建立起一個(gè)單向的通信管道,且這種關(guān)系只能由父進(jìn)程來建立。因此,每個(gè)管道都是單向的,當(dāng)需要雙向通信時(shí)就需要建立起兩個(gè)管道。管道兩端的進(jìn)程均將該管道看做一個(gè)文件,一個(gè)進(jìn)程負(fù)責(zé)往管道中寫內(nèi)容,而另一個(gè)從管道中讀取。這種傳輸遵循“先入先出”(FIFO)的規(guī)則。

●     命名管道

命名管道是為了解決無名管道只能用于近親進(jìn)程之間通信的缺陷而設(shè)計(jì)的。命名管道是建立在實(shí)際的磁盤介質(zhì)或文件系統(tǒng)(而不是只存在于內(nèi)存中)上有自己 名字的文件,任何進(jìn)程可以在任何時(shí)間通過文件名或路徑名與該文件建立聯(lián)系。為了實(shí)現(xiàn)命名管道,引入了一種新的文件類型——FIFO文件(遵循先進(jìn)先出的原 則)。實(shí)現(xiàn)一個(gè)命名管道實(shí)際上就是實(shí)現(xiàn)一個(gè)FIFO文件。命名管道一旦建立,之后它的讀、寫以及關(guān)閉操作都與普通管道完全相同。雖然FIFO文件的 inode節(jié)點(diǎn)在磁盤上,但是僅是一個(gè)節(jié)點(diǎn)而已,文件的數(shù)據(jù)還是存在于內(nèi)存緩沖頁面中,和普通管道相同。

2、環(huán)形緩沖區(qū)

每個(gè)管道只有一個(gè)頁面作為緩沖區(qū),該頁面是按照環(huán)形緩沖區(qū)的方式來使用的。這種訪問方式是典型的“生產(chǎn)者——消費(fèi)者”模型。當(dāng)“生產(chǎn)者”進(jìn)程有大量 的數(shù)據(jù)需要寫時(shí),而且每當(dāng)寫滿一個(gè)頁面就需要進(jìn)行睡眠等待,等待“消費(fèi)者”從管道中讀走一些數(shù)據(jù),為其騰出一些空間。相應(yīng)的,如果管道中沒有可讀數(shù)據(jù), “消費(fèi)者”進(jìn)程就要睡眠等待。

2.1環(huán)形緩沖區(qū)實(shí)現(xiàn)原理

環(huán)形緩沖區(qū)是嵌入式系統(tǒng)中一個(gè)常用的重要數(shù)據(jù)結(jié)構(gòu)。一般采用數(shù)組形式進(jìn)行存儲,即在內(nèi)存中申請一塊連續(xù)的線性空間,可以在初始化的時(shí)候把存儲空間一 次性分配好。只是要模擬環(huán)形,必須在邏輯上把數(shù)組的頭尾相連接。只要對數(shù)組最后一個(gè)元素進(jìn)行特殊的處理——訪問尾部元素的下一元素時(shí),重新回到頭部元素。 對于從尾部回到頭部只需模緩沖長度即可(假設(shè)maxlen為環(huán)形緩沖的長度,當(dāng)讀指針read指向尾部元素時(shí),只需執(zhí)行read=read%maxlen 即可使read回到頭部元素)。

2.2讀寫操作

環(huán)形緩沖區(qū)要維護(hù)寫端(write)和讀端(read)兩個(gè)索引。寫入數(shù)據(jù)時(shí),必須先確保緩沖區(qū)沒有滿,然后才能將數(shù)據(jù)寫入,最后將write指針 指向下一個(gè)元素;讀取數(shù)據(jù)時(shí),首先要確保緩沖區(qū)不為空,然后返回read指針對應(yīng)得元素,最后使read指向下一個(gè)元素的位置。讀寫操作偽代碼:

2.3判斷“滿”和“空”

當(dāng)read和write指向同一個(gè)位置時(shí)環(huán)形緩沖區(qū)為空或滿。為了區(qū)別環(huán)滿和空,當(dāng)read和write重疊的時(shí)候環(huán)空;而當(dāng)write比read快,追到距離read還有一個(gè)元素間隔的時(shí)候,就認(rèn)為環(huán)已經(jīng)滿了。環(huán)形緩沖區(qū)原理圖如圖3所示。

3 并發(fā)訪問

考慮到在不同環(huán)境下,任務(wù)可能對環(huán)形緩沖區(qū)的訪問情況不同,需要對并發(fā)訪問的情況進(jìn)行分析。

在單任務(wù)環(huán)境下,只存在一個(gè)讀任務(wù)和一個(gè)寫任務(wù),只要保證寫任務(wù)可以順利的完成將數(shù)據(jù)寫入,而讀任務(wù)可以及時(shí)的將數(shù)據(jù)讀出即可。如果有競爭發(fā)生,可能會(huì)出現(xiàn)如下情況:

Case1:假如寫任務(wù)在“寫指針加1,指向下一個(gè)可寫空位置”執(zhí)行完成時(shí)被打斷,如圖3所示,此時(shí)寫指針write指向非法位置。當(dāng)系統(tǒng)調(diào)度讀任 務(wù)執(zhí)行時(shí),如果讀任務(wù)需要讀多個(gè)數(shù)據(jù),那么不但應(yīng)該讀出的數(shù)據(jù)被讀出,而且當(dāng)讀指針被調(diào)整為0是,會(huì)將以前已經(jīng)讀出的數(shù)據(jù)重復(fù)讀出。

Case2:假設(shè)讀任務(wù)進(jìn)行讀操作,在“讀指針加1”執(zhí)行完時(shí)被打斷,如圖4所示,此時(shí)read所處的位置是非法的。當(dāng)系統(tǒng)調(diào)度寫任務(wù)執(zhí)行時(shí),如果 寫任務(wù)要寫多個(gè)數(shù)據(jù),那么當(dāng)寫指針指到尾部時(shí),本來緩沖區(qū)應(yīng)該為滿狀態(tài),不能再寫,但是由于讀指針處于非法位置,在讀任務(wù)執(zhí)行前,寫任務(wù)會(huì)任務(wù)緩沖區(qū)為 空,繼續(xù)進(jìn)行寫操作,將覆蓋還沒有來的及讀出的數(shù)據(jù)。

為了避免上述錯(cuò)誤的發(fā)生,必須保證讀寫指針操作是原子性的,讀寫指針的值要么是沒有修改的,要么是修改正確的。可以引入信號量,有效的保護(hù)臨界區(qū)代碼,就可以避免這些問題。在單任務(wù)環(huán)境下,也可以通過采取適當(dāng)?shù)拇胧﹣肀苊庑盘柫康氖褂?,從而提高程序的?zhí)行效率。


4.linux內(nèi)核中pipe的讀寫實(shí)現(xiàn)

Linux內(nèi)核中采用struct pipe_inode_info結(jié)構(gòu)體來描述一個(gè)管道。

其中,當(dāng)pipe為空/滿時(shí),采用等待隊(duì)列,該隊(duì)列使用自旋鎖進(jìn)行保護(hù)。

用struct Pipe_buffer數(shù)據(jù)結(jié)構(gòu)描述pipe的緩沖(buffer)

本文重點(diǎn)針對pipe實(shí)現(xiàn)中對環(huán)形緩沖區(qū)的操作方法,目的是借鑒學(xué)習(xí)其互斥訪問方法。因此,著重分析pipe_read和pipe_write方法。

●Pipe_read(fs/pipe.c)

訪問pipe對應(yīng)的inode必須獲得相應(yīng)的互斥鎖,防止并發(fā)訪問。

數(shù)據(jù)的讀出放在一個(gè)死循環(huán)中,整個(gè)for循環(huán)中的代碼均屬于臨界區(qū),需要互斥鎖進(jìn)行保護(hù)。

有以下幾種情況才會(huì)退出:

▲     完成數(shù)據(jù)的讀出;

▲     Pipe沒有writer進(jìn)程

▲     進(jìn)程設(shè)置了O_NONBLOCK標(biāo)志

325行將buffer中的數(shù)據(jù)讀出。完成后,緊接著調(diào)整buffer中指針的位置

其中,348行設(shè)置標(biāo)志,do_wakeup為1,說明buffer中已經(jīng)有空位置可以寫入數(shù)據(jù),這時(shí),可以喚醒等待隊(duì)列中的睡眠的寫進(jìn)程。

如果沒有退出,或者成功讀取數(shù)據(jù),讀進(jìn)程會(huì)主動(dòng)調(diào)用pipe_wait函數(shù)進(jìn)行睡眠等待,直到有writer進(jìn)程寫入數(shù)據(jù)并將其喚醒。

  

當(dāng)進(jìn)程從臨界區(qū)中退出后會(huì)釋放互斥鎖。

 

最后,為了防止reader進(jìn)程是因?yàn)槭盏叫盘柫慷顺觯俳o睡眠的writer進(jìn)程一次機(jī)會(huì),檢查do_wakeup,如果為1就喚醒睡眠的writer進(jìn)程。

●     pipe_write(fs/pipe.c)

首先,與pipe_read相同,pipe_write采用互斥鎖對臨界區(qū)進(jìn)行保護(hù)。寫操作也放在死循環(huán)中,退出條件也與read相同。

與pipe_read不同,writer進(jìn)程不總是睡眠等待,在調(diào)用pipe_wait進(jìn)行睡眠后,如果有read進(jìn)程讀走某些數(shù)據(jù),write進(jìn)程會(huì)隨時(shí)進(jìn)行寫操作。


    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多