日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

Linux进程间通信分类 以及 pipe的原理实现

發(fā)布時(shí)間:2024/9/30 linux 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux进程间通信分类 以及 pipe的原理实现 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

http://blog.sina.com.cn/s/blog_4a84bd960100by8s.html

http://home.lupaworld.com/home-space-uid-296848-do-blog-id-230801.html

一個(gè)大型的應(yīng)用系統(tǒng),往往需要眾多進(jìn)程協(xié)作,進(jìn)程(Linux進(jìn)程概念見(jiàn)附1)間通信的重要性顯而易見(jiàn)。本系列文章闡述了Linux環(huán)境下的幾種主要進(jìn)程間通信手段,并針對(duì)每個(gè)通信手段關(guān)鍵技術(shù)環(huán)節(jié)給出詳細(xì)實(shí)例。為達(dá)到闡明問(wèn)題的目的,本文還對(duì)某些通信手段的內(nèi)部實(shí)現(xiàn)機(jī)制進(jìn)行了分析。

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



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

圖一給出了linux 所支持的各種IPC手段,在本文接下來(lái)的討論中,為了避免概念上的混淆,在盡可能少提及Unix的各個(gè)版本的情況下,所有問(wèn)題的討論最終都會(huì)歸結(jié)到Linux環(huán)境下的進(jìn)程間通信上來(lái)。并且,對(duì)于Linux所支持通信手段的不同實(shí)現(xiàn)版本(如對(duì)于共享內(nèi)存來(lái)說(shuō),有Posix共享內(nèi)存區(qū)以及System V共享內(nèi)存區(qū)兩個(gè)實(shí)現(xiàn)版本),將主要介紹Posix API。

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

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

  • 簡(jiǎn)介:本文主要介紹了管道(pipe)的基本概念和用途;分析了環(huán)形緩沖區(qū)的存儲(chǔ)、訪問(wèn)及其實(shí)現(xiàn)方法;分析并發(fā)訪問(wèn)可能引發(fā)的問(wèn)題,并給出解決方法;分析了linux2.6.29內(nèi)核中pipe的讀寫(xiě)函數(shù)。

    1、管道(pipe)

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

    ●?????無(wú)名管道

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

    ●?????命名管道

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

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

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

    圖1?生產(chǎn)者——消費(fèi)者關(guān)系圖

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

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

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

    2.2讀寫(xiě)操作

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

    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?環(huán)形緩沖區(qū)實(shí)現(xiàn)原理圖

    3?并發(fā)訪問(wèn)

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

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

    Case1:假如寫(xiě)任務(wù)在“寫(xiě)指針加1,指向下一個(gè)可寫(xiě)空位置”執(zhí)行完成時(shí)被打斷,如圖3所示,此時(shí)寫(xiě)指針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ù)讀出。

    圖4?寫(xiě)指針?lè)欠?/p>

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

    圖5?讀指針?lè)欠?/p>

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

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

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

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

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

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

    ●Pipe_read(fs/pipe.c)

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

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

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

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

    ▲?????Pipe沒(méi)有writer進(jìn)程

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

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

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

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

    ??

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

    ?

    最后,為了防止reader進(jìn)程是因?yàn)槭盏叫盘?hào)量而退出,再給睡眠的writer進(jìn)程一次機(jī)會(huì),檢查do_wakeup,如果為1就喚醒睡眠的writer進(jìn)程。

    ●?????pipe_write(fs/pipe.c)

    首先,與pipe_read相同,pipe_write采用互斥鎖對(duì)臨界區(qū)進(jìn)行保護(hù)。寫(xiě)操作也放在死循環(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)行寫(xiě)操作。


    總結(jié)

    以上是生活随笔為你收集整理的Linux进程间通信分类 以及 pipe的原理实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。