1. 程式人生 > >Linux程序間通訊之POSIX共享記憶體

Linux程序間通訊之POSIX共享記憶體

共享記憶體是最高效的IPC機制,因為它不涉及程序之間的任何資料傳輸。這種高效率帶來的問題是,我們必須用其他輔助手段來同步程序對共享記憶體的訪問,否則會產生競態條件。因此,共享記憶體通常和其他程序間通訊方式一起使用。
Linux下有三種共享記憶體的IPC技術:System V共享記憶體、共享檔案對映(mmap)、POSIX共享記憶體。
我們在這裡只介紹POSIX共享記憶體。

要使用POSIX共享記憶體物件需要完成下列任務。

  1. 使用shm_open()函式開啟一個與指定的名字對應的物件。shm_open()函式與open()系統呼叫類似,它會建立一個新的共享物件或開啟一個既有物件。作為函式結果,shm_open()會返回一個引用該物件的檔案描述符。
  2. 將上一步中獲得的檔案描述符傳入mmap()呼叫並在其flags引數中指定MAP_SHARED。這會將共享記憶體物件對映進程序的虛擬地址空間。與mmap()的其他用法一樣,一旦映射了物件之後就能夠關閉該檔案描述符而不會影響到這個對映。

建立共享記憶體物件

shm_open()函式建立和開啟一個新的共享記憶體物件或開啟一個既有物件。傳入shm_open()的引數與傳入open()的引數類似。

#include<fcntl.h>
#include<sys/stat.h>
#include<sys/mman.h>

int shm_open(const
char *name,int oflag,mode_t mode);

name引數標識出了待建立或待開啟的共享記憶體物件。oflag引數是一個改變呼叫行為的位掩碼。
oflag引數的位值

標記 描述
O_CREAT 物件不存在時建立物件
O_EXCL 與O_CREAT互斥地建立物件
O_RDONLY 開啟只讀訪問
O_RDWR 開啟讀寫訪問
O_TRUNC 將物件長度截斷為零

oflag引數的用途之一是確定是開啟一個既有的共享記憶體物件還是建立並開啟一個新物件。同時指定O_EXCL和O_CREAT能夠確保呼叫者是物件的建立者,如果物件已經存在,那麼就返回一個錯誤(EEXIST)。
oflag引數還表明了呼叫程序在共享記憶體物件上的訪問模式,其取值為O_RDONLY或O_RDWR。

在一個新共享記憶體物件被建立時,其所有權和組所有權將根據呼叫shm_open()的程序的有效使用者和組ID來設定,物件許可權將會根據mode引數中設定的掩碼值來設定。
與open()系統呼叫一樣,mode中的許可權掩碼將會根據程序的umask來取值。與open()不同的是,在呼叫shm_open()時總是需要mode引數,在不建立新物件時需要將這個引數值指定為0。
shm_open()返回的檔案描述符會設定close-on-exec標記,因此當程式執行了一個exec()時檔案描述符會被自動關閉。
一個新共享記憶體物件被建立時其初始長度會被設定為0。這意味著建立完一個新共享記憶體物件之後通常在呼叫mmap()之前需要呼叫ftruncate()來設定物件的大小。在呼叫完mmap()之後可能還需要使用ftruncate()來根據需求擴大或收縮共享記憶體物件。
在擴充套件一個共享記憶體物件時,新增加的位元組會自動被初始化為0。

使用共享記憶體

使用步驟:
1. 呼叫shm_open()函式建立或開啟一個共享記憶體物件。
2. 呼叫ftruncate()調整物件大小。
3. 呼叫mmap()函式,將記憶體對映到相應的程序虛擬記憶體中。
mmap()系統呼叫在呼叫程序的虛擬地址空間中建立一個新對映。

#include<sys/mman.h>

void *mmap(void *addr,size_t length,int prot,int flags,int fd,off_t offset);

addr引數指定了對映被置放的虛擬地址。如果將addr指定為NULL,那麼核心會為對映選擇一個合適的地址。這是建立對映的首選做法。或者在addr中指定一個非NULL值時,核心會在選擇將對映放置在何處時將這個引數值作為一個提示資訊來處理。在實踐中,核心至少會將指定的地址舍入到最近的一個分頁邊界處。
length引數指定了對映的位元組數。
prot引數是一個位掩碼,其取值見下表:

描述
PROT_NONE 區域無法訪問
PROT_READ 區域內容可讀取
PROT_WRITE 區域內容可修改
PROT_EXEC 區域內容可執行

flags引數是一個控制對映操作各個方面的選項的位掩碼。這裡我們要設定為MAP_SHARED。
fd引數我們傳入shm_open返回的描述符。
offset引數代表偏移量,設定為0代表從對映檔案的開頭開始對映。

程式碼示例

下面兩個程式演示瞭如何使用一個共享記憶體物件將資料從一個程序傳輸到另一個程序中。
第一個程式將資料寫入到共享記憶體中,第二個程式將資料從共享記憶體中讀出。
使用gcc編譯時,末尾加上 -lrt。

1.

/*************************************************************************
    > File Name: 1.c
    > Author:fengxin 
    > Mail:[email protected] 
    > Created Time: 2017年08月02日 星期三 17時49分03秒
 ************************************************************************/

#include<stdio.h>
#include<string.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/stat.h>
#include <unistd.h>

int main()
{
    int fd;
    char *addr;
    fd=shm_open("test",O_RDWR|O_CREAT,0777);   //建立共享記憶體物件
    if(fd<0)
    {
        printf("shm_open error\n");
    }

    char string[20]="Hello world";
    if(ftruncate(fd,strlen(string))==-1)    //改變物件大小
    {
        printf("ftruncate error\n");
    }

    addr=mmap(NULL,strlen(string),PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);  //記憶體對映
    if(addr==MAP_FAILED)
    {
        printf("mmap error\n");
    }

    memcpy(addr,string,strlen(string));  //拷貝字串到共享記憶體中

    close(fd);

    return 0;


}

2.

/*************************************************************************
    > File Name: 1.c
    > Author:fengxin 
    > Mail:[email protected] 
    > Created Time: 2017年08月02日 星期三 17時49分03秒
 ************************************************************************/

#include<stdio.h>
#include<string.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/stat.h>
#include<unistd.h>

int main()
{
    int fd;
    char *addr;
    struct stat sb;
    fd=shm_open("test",O_RDWR,0);   //建立共享記憶體物件
    if(fd<0)
    {
        printf("shm_open error\n");
    }


    if(fstat(fd,&sb)==-1)
    {
        printf("fstat error\n");
    }

    addr=mmap(NULL,sb.st_size,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);  //記憶體對映
    if(addr==MAP_FAILED)
    {
        printf("mmap error\n");
    }

    write(STDOUT_FILENO,addr,sb.st_size);  //拷貝字串到共享記憶體中

    close(fd);

    return 0;
}

相關推薦

Linux程序通訊POSIX共享記憶體

共享記憶體是最高效的IPC機制,因為它不涉及程序之間的任何資料傳輸。這種高效率帶來的問題是,我們必須用其他輔助手段來同步程序對共享記憶體的訪問,否則會產生競態條件。因此,共享記憶體通常和其他程序間通訊方式一起使用。 Linux下有三種共享記憶體的IPC技術:S

程序通訊共享記憶體

  8.5.1  共享記憶體概述   可以說,共享記憶體是一種最為高效的程序間通訊方式。因為程序可以直接讀寫記憶體,不需要任何資料的複製。為了在多個程序間交換資訊,核心專門留出了一塊記憶體區。這段記憶體區可以由需要訪問的程序將其對映到自己的私有地址空間。因此,程序就可以直接讀寫這一記憶體區而不需要進行資料的

Linux程序通訊POSIX訊息佇列

訊息佇列可認為是一個訊息連結串列,它允許程序之間以訊息的形式交換資料。有足夠寫許可權的程序或執行緒可往佇列中放置訊息,有足夠讀許可權的程序或執行緒可從佇列中取走訊息。每個訊息都是一個記錄,它由傳送者賦予一個優先順序。與管道不同,管道是位元組流模型,沒有訊息邊界。

Linux程序通訊訊號量(semaphore)、訊息佇列(Message Queue)和共享記憶體(Share Memory)

System V 程序通訊方式:訊號量(semaphore)、訊息佇列(Message Queue)和共享記憶體(Share Memory) 訊號量 訊號量(semaphore)實際是一個整數,它的值由多個程序進行測試(test)和設定(set)。就每個程序所關心的測試和

Linux(高階程式設計)8————程序通訊4(共享記憶體

共享記憶體是什麼? 因為程序之間是相互獨立的,他們有各自程序地址空間,那麼他們需要通訊時就要藉助核心來為他們建立橋樑,像之前我們瞭解的管道、訊息佇列就是核心做的工作來為程序間通訊架的橋樑。共享記憶體也是核心為程序間通訊駕的一座橋樑,只不過這座橋樑比其他橋樑更優,共享記憶體是核心為需要通訊

linux開發】程序通訊命名管道-共享記憶體-記憶體對映-訊息佇列-訊號量

程序間通訊命名管道-共享記憶體-記憶體對映-訊息佇列-訊號量  在Unix平臺上,建立命名管道是建立了一個fifo檔案,和在shell下面用mkfifo命令的效果是一樣的。看起來這個管道檔案就是一個普通的檔案系統瓜掛載點,但是它只不過是作為一個名稱存在,實際的內容是一塊系統

linux 程序通訊FIFO

1.概述 FIFO與管道幾乎類似,所以FIFO也是一個位元組流,從FIFO讀取的順序也是與被寫入FIFO的順序一致,容量是也有限的,也是可以確保寫入不超過PIPE_BUF位元組的操作是原子的,FIFO的本質也是一個管道,但傳遞方向是可以雙向的,它們兩者之間的最大差別在於FIFO在檔案系統中擁有一個名稱,並且

LinuxLinux程序通訊訊息佇列

1、訊息佇列概念引入    訊息佇列提供了一個從一個程序向另外一個程序傳送一塊資料的方法每個資料塊都被認為是有一個型別,接收者程序接收的資料塊可以有不同的型別值訊息佇列也有管道一樣的不足,就是每個訊息的最大長度是有上限的(MSG

Linux程序通訊訊號通訊

訊號通訊是Linux程序間通訊的一種方式。 1.什麼是訊號? 訊號是系統響應某些條件而產生的一個事件,接收到該訊號的程序會相應地採取一些措施。例如我們在windows系統中想強制結束一個程式我們需要用到的是工作管理員,而在Linux中,我們是通過訊號來實現的,執

Linux程序通訊pipe

1、管道(PIPE)        從概念上說,管道是兩個程序之間的一個connection,因此一個程序的標準輸出就變成了另一個程序的標準輸入。在Unix作業系統中,管道用於程序間通訊(inter-process communication). (1

Nginx原始碼分析與實踐---程序通訊機制(共享記憶體

Nginx有一個master程序和多個worker程序,那麼master程序與worker程序間或worker程序之間是如何通訊的呢,又什麼時候需要程序間通訊呢? 我們知道linux下的程序間通訊方式主要有:管道、FIFO、套接字、訊息佇列、共享記憶體、訊號。那麼nginx的程序間通訊方式採

Linux程序通訊——管道(整理)

 程序間通訊 fork pipe pie_t 等用法(管道機制 通訊) 每個程序各自有不同的使用者地址空間,任 何一個程序的全域性變數在另一個程序中都看不到,所以程序之間要交換資料必須通過核心,在核心中開闢一塊緩衝 區,程序1把資料從使用者空間拷到核心緩衝區,程序2再從

linux 程序通訊訊號

Linux訊號(signal) 機制分析 轉載至:https://www.cnblogs.com/hoys/archive/2012/08/19/2646377.html 【摘要】本文分析了Linux核心對於訊號的實現機制和應

Linux -- 程序通訊管道

管道是Linux裡的一種檔案型別,同時也是Linux系統下程序間通訊的一種方式 建立一個管道檔案有兩種方式: 1.  Shell 下命令 mkfifo + filename,即建立一個有名管道 2.

Linux 程序通訊管道

程序之間的通訊之管道 目錄 1 無名管道    管道是一種最基本的IPC機制,作用於父子程序之間,完成資料傳遞。 管道有以下特性: 1.其本質是一個偽檔案(實為核心緩衝區)其本質是一個偽檔案(實為核心緩衝區) 2.由兩

程序通訊方式一 共享記憶體

共享記憶體 共享記憶體是程序間通訊中最簡單的方式之中的一個。 共享記憶體是系統出於多個程序之間通訊的考慮,而預留的的一塊記憶體區。 共享記憶體同意兩個或很多其他程序訪問同一塊記憶體,就如同 malloc() 函式向不同程序返回了指向同一個實體記憶體區域的指標。 當一個

linux程序通訊訊號量(semaphore)

==================================================== 訊號量(semaphore)簡介 當我們在多使用者系統,多程序系統,或是兩者混合的系統中使用執行緒操作編寫程式時,我們經常會發現我們有段臨界程式碼,在此處我們需要

程序通訊Linux共享記憶體程式設計

共享記憶體 共享記憶體(Shared Memory)是指多個程序共享一段指定的記憶體空間進行資料互動,三種System V IPC機制(另外兩種是訊號量和訊息佇列)中共享記憶體是速度最快的一種。 共享記憶體機制是最快的一種程序間通訊(Interprocess Commun

程序通訊-共享記憶體Shared Memory--linux核心剖析(十一)

共享記憶體 共享記憶體是程序間通訊中最簡單的方式之一。 共享記憶體是系統出於多個程序之間通訊的考慮,而預留的的一塊記憶體區。 共享記憶體允許兩個或更多程序訪問同一塊記憶體,就如同 malloc() 函式向不同程序返回了指向同一個實體記憶體區域的指標。當

Linux---程序通訊IPC共享記憶體

程序間通訊(IPC):是指在不同程序之間傳播或交換資訊。 IPC的方式:通常有管道(無名管道、命名管道)、訊息佇列、訊號量、共享儲存、Socket、Streams等(Socket和Streams支援不同主機上的兩個程序IPC) 程序間通訊的目的: 1