linux網路編程之POSIX 共用記憶體和 系列函數

來源:互聯網
上載者:User

在前面介紹了system v 共用記憶體的相關知識,現在來稍微看看posix 共用記憶體 和系列函數。

共用記憶體簡單來說就是一塊真正的實體記憶體地區,可以使用一些函數將這塊區域對應到進程的地址空間進行讀寫,而posix 共用記憶體與system v 共用記憶體不同的是它是用虛擬檔案系統(tmpfs)實現的,已經掛載在/dev/shm 下面。man 7 shm_overview


下面來看系列函數,編譯時間候加上 -lrt 選項,即串連librt 庫 (即時庫)


功能:用來建立或開啟一個共用記憶體對象
原型 int shm_open(const char *name, int oflag, mode_t mode); 
參數
name:共用記憶體對象的名字,必須以/打頭,並且後續不能有其它/ ,形如/somename長度不能超過NAME_MAX(255)
oflag:與open函數類似,可以是O_RDONLY、O_RDWR,還可以按位或上O_CREAT、O_EXCL、O_TRUNC等。
mode:此參數總是需要設定,如果oflag沒有指定了O_CREAT,可以指定為0
傳回值:成功返回非負整數檔案描述符;失敗返回-1


注意,不存在所謂的shm_close 函數,可以直接使用close 來關閉檔案描述符。


功能:修改共用記憶體對象大小,shm_open不像shmget一樣可以設定共用記憶體的大小,但可以使用ftruncate 設定大小。
原型 int ftruncate(int fd, off_t length);
參數
fd: 檔案描述符
length:長度
傳回值:成功返回0;失敗返回-1


功能:擷取共用記憶體對象資訊
原型
int fstat(int fd, struct stat *buf);
參數
fd: 檔案描述符
buf:返回共用記憶體狀態
傳回值:成功返回0;失敗返回-1

struct stat 可以參考這裡。

類似 shm_ctl(,IPC_STAT,);


功能:刪除一個共用記憶體對象
原型 int shm_unlink(const char *name); 
參數
name: 共用記憶體對象的名字
傳回值:成功返回0;失敗返回-1

shm_unlink 類似 shm_ctl(,IPC_RMID,);


功能:將共用記憶體對象映射到進程地址空間。
原型 void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
參數
addr: 要映射的起始地址,通常指定為NULL,讓核心自動選擇
len:映射到進程地址空間的位元組數
prot:映射區保護方式
flags:標誌
fd:檔案描述符
offset:從檔案頭開始的位移量
傳回值:成功返回映射到的記憶體區的起始地址;失敗返回-1

在前面曾經介紹了mmap 函數 將檔案對應到進程地址空間的作用,其實它還可以將共用記憶體對象映射到進程地址空間,類似shmat的作用,只是傳入的檔案描述符fd 是shm_open 返回的。同樣地,解除映射可以用munmap,類似shmdt
的作用。


下面寫幾個程式來示範一下:

shm_open.c

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/mman.h>

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

int main(void)
{
    int  shmid;
    shmid = shm_open("/xyz", O_CREAT | O_RDWR, 0666);
    if (shmid == -1)
        ERR_EXIT("shm_open");
    if (ftruncate(shmid, 36) == -1)
        ERR_EXIT("ftruncate");

    struct stat buf;
    if (fstat(shmid, &buf) == -1)
        ERR_EXIT("fstat");

    printf("size=%ld, mode=%o\n", buf.st_size, buf.st_mode & 0777);
    close(shmid);
    return 0;
}

simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./shm_open 
size=36, mode=664
simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ls -l /dev/shm/xyz 
-rw-rw-r-- 1 simba simba 36 Jun 16 15:01 /dev/shm/xyz

即建立了一個36位元組的共用記憶體段,在/dev/shm 目錄下。


shm_write.c

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<string.h>

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

typedef struct stu
{
    char name[32];
    int age;
} STU;

int main(void)
{
    int  shmid;
    shmid = shm_open("/xyz", O_RDWR, 0);
    if (shmid == -1)
        ERR_EXIT("shm_open");

    struct stat buf;
    if (fstat(shmid, &buf) == -1)
        ERR_EXIT("fstat");

    printf("size=%ld, mode=%o\n", buf.st_size, buf.st_mode & 0777);

    STU *p;
    p = (STU *)mmap(NULL, buf.st_size, PROT_WRITE, MAP_SHARED, shmid, 0);
    if (p == MAP_FAILED)
        ERR_EXIT("mmap");

    strcpy(p->name, "test");
    p->age = 20;

    close(shmid);
    return 0;
}

simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./shm_write 
size=36, mode=664
simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ od -c /dev/shm/xyz 
0000000   t   e   s   t  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000020  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000040 024  \0  \0  \0
0000044

使用mmap 將共用記憶體映射到進程地址空間,將shmid 傳入fd 參數,其餘跟檔案對應沒什麼區別,od -c查看可以看到寫入的東西。


shm_read.c

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<string.h>

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

typedef struct stu
{
    char name[32];
    int age;
} STU;

int main(void)
{
    int  shmid;
    shmid = shm_open("/xyz", O_RDONLY, 0);
    if (shmid == -1)
        ERR_EXIT("shm_open");

    struct stat buf;
    if (fstat(shmid, &buf) == -1)
        ERR_EXIT("fstat");

    printf("size=%ld, mode=%o\n", buf.st_size, buf.st_mode & 0777);

    STU *p;
    p = (STU *)mmap(NULL, buf.st_size, PROT_READ, MAP_SHARED, shmid, 0);
    if (p == MAP_FAILED)
        ERR_EXIT("mmap");

    printf("name=%s age=%d\n", p->name, p->age);
    close(shmid);
    return 0;
}

simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./shm_read 
size=36, mode=664
name=test age=20

即讀取到了共用記憶體的資料,注意,讀取資料後共用記憶體的資料還是存在的,除非被覆蓋了。


參考:《UNP》


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.