Linux进程间通信(四) - 共享内存
共享內(nèi)存的優(yōu)勢
采用共享內(nèi)存通信的一個顯而易見的好處是效率高,因為進程可以直接讀寫內(nèi)存,而不需要任何數(shù)據(jù)的拷貝。對于像管道和消息隊列等通信方式,則需要在內(nèi)核和用戶空間進行四次的數(shù)據(jù)拷貝,而共享內(nèi)存則只拷貝兩次數(shù)據(jù):一次從輸入文件到共享內(nèi)存區(qū),另一次從共享內(nèi)存區(qū)到輸出文件。實際上,進程之間在共享內(nèi)存時,并不總是讀寫少量數(shù)據(jù)后就解除映射,有新的通信時,再重新建立共享內(nèi)存區(qū)域。而是保持共享區(qū)域,直到通信完畢為止,這樣,數(shù)據(jù)內(nèi)容一直保存在共享內(nèi)存中,并沒有寫回文件。共享內(nèi)存中的內(nèi)容往往是在解除映射時才寫回文件的。因此,采用共享內(nèi)存的通信方式效率是非常高的。
圖1:POSIX消息隊列
圖2:共享內(nèi)存
Linux的2.6.x內(nèi)核支持多種共享內(nèi)存方式,如mmap()系統(tǒng)調(diào)用,Posix共享內(nèi)存,以及System V共享內(nèi)存。本文對3種共享內(nèi)存形式都將進行介紹。
mmap調(diào)用
mmap()系統(tǒng)調(diào)用使得進程之間通過映射同一個普通文件實現(xiàn)共享內(nèi)存。普通文件被映射到進程地址空間后,進程可以像訪問普通內(nèi)存一樣對文件進行訪問,不必再調(diào)用read(),write()等操作。
注:實際上,mmap()系統(tǒng)調(diào)用并不是完全為了用于共享內(nèi)存而設(shè)計的。它本身提供了不同于一般對普通文件的訪問方式,進程可以像讀寫內(nèi)存一樣對普通文件的操作。而Posix或System V的共享內(nèi)存IPC則純粹用于共享目的,當(dāng)然mmap()實現(xiàn)共享內(nèi)存也是其主要應(yīng)用之一。
圖3:直接映射文件
圖4:開辟共享內(nèi)存空間
linux采用的是頁式管理機制。對于用mmap()映射普通文件來說,進程會在自己的地址空間新增一塊空間,空間大小由mmap()的length參數(shù)指定,注意,進程并不一定能夠?qū)θ啃略隹臻g都能進行有效訪問。進程能夠訪問的有效地址大小取決于文件被映射部分的大小。簡單的說,能夠容納文件被映射部分大小的最少頁面?zhèn)€數(shù)決定了進程從mmap()返回的地址開始,能夠有效訪問的地址空間大小。超過這個空間大小,內(nèi)核會根據(jù)超過的嚴(yán)重程度返回發(fā)送不同的信號給進程。如下圖所示:
圖5:mmap映射
這個具體差異跟系統(tǒng)實現(xiàn)有關(guān),這里不做詳細(xì)討論。
數(shù)據(jù)結(jié)構(gòu)
文件詳細(xì)信息
struct stat {
?? dev_t???? st_dev;???? /* ID of device containing file */
?? ino_t???? st_ino;???? /* inode number */
?? mode_t??? st_mode;??? /* protection */
?? nlink_t?? st_nlink;?? /* number of hard links */
?? uid_t???? st_uid;???? /* user ID of owner */
?? gid_t???? st_gid;???? /* group ID of owner */
?? dev_t???? st_rdev;??? /* device ID (if special file) */
?? off_t???? st_size;??? /* total size, in bytes */
?? blksize_t st_blksize; /* blocksize for file system I/O */
?? blkcnt_t? st_blocks;? /* number of 512B blocks allocated */
?? time_t??? st_atime;?? /* time of last access */
?? time_t??? st_mtime;?? /* time of last modification */
?? time_t??? st_ctime;?? /* time of last status change */
};
函數(shù)說明
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
void *mmap64(void *addr, size_t length, int prot, int flags, int fd, off64_t offset);
?? fd:為即將映射到進程空間的文件描述字,一般由open()返回,同時,fd可以指定為-1,此時須指定flags參數(shù)中的MAP_ANON,表明進行的是匿名映射(不涉及具體的文件名,避免了文件的創(chuàng)建及打開,很顯然只能用于具有親緣關(guān)系的進程間通信)。
?? Length:映射到調(diào)用進程地址空間的字節(jié)數(shù),它從被映射文件開頭offset個字節(jié)開始算起。prot:指定共享內(nèi)存的訪問權(quán)限??扇∪缦聨讉€值的或:PROT_READ(可讀),PROT_WRITE(可寫),PROT_EXEC(可執(zhí)行),PROT_NONE(不可訪問)。
?? flags:由以下幾個常值指定MAP_SHARED, MAP_PRIVATE, MAP_FIXED等,其中,MAP_SHARED, MAP_PRIVATE必選其一,而MAP_FIXED則不推薦使用。
ü? MAP_SHARED 對映射區(qū)域的寫入數(shù)據(jù)會復(fù)制回文件內(nèi),而且允許其他映射該文件的進程共享。
ü? MAP_PRIVATE 對映射區(qū)域的寫入操作會產(chǎn)生一個映射文件的復(fù)制,即私人的“寫入時復(fù)制”(copy on write)對此區(qū)域作的任何修改都不會寫回原來的文件內(nèi)容。
ü? MAP_FIXED 如果參數(shù)start所指的地址無法成功建立映射時,則放棄映射,不對地址做修正。通常不鼓勵用此旗標(biāo)。
ü? MAP_ANONYMOUS 建立匿名映射。此時會忽略參數(shù)fd,不涉及文件,而且映射區(qū)域無法和其他進程共享。
ü? MAP_LOCKED 將映射區(qū)域鎖定住,這表示該區(qū)域不會被置換(swap)。
?? offset:一般設(shè)為0,表示從文件頭開始映射。
?? addr:指定文件應(yīng)被映射到進程空間的起始地址,一般被指定一個空指針,此時選擇起始地址的任務(wù)留給內(nèi)核來完成。函數(shù)的返回值為最后文件映射到進程空間的地址,進程可直接操作起始地址為該值的有效地址。
?
int munmap(void *addr, size_t length);
該調(diào)用在進程地址空間中解除一個映射關(guān)系,addr是調(diào)用mmap()時返回的地址,length是映射區(qū)的大小。當(dāng)映射關(guān)系解除后,對原來映射地址的訪問將導(dǎo)致段錯誤發(fā)生。
?
int msync(void *addr, size_t length, int flags);
一般說來,進程在映射空間的對共享內(nèi)容的改變并不直接寫回到磁盤文件中,往往在調(diào)用munmap()后才執(zhí)行該操作??梢酝ㄟ^調(diào)用msync()實現(xiàn)磁盤上文件內(nèi)容與共享內(nèi)存區(qū)的內(nèi)容一致。
?
// 調(diào)整fd所指的文件的大小到length
int ftruncate(int fd, off_t length);
?
// 獲取fd所指的文件的詳細(xì)信息
int fstat(int fd, struct stat *buf);
代碼說明
寫共享內(nèi)存
#include <sys/mman.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h>typedef struct {char name[32];int age; } people;main(int argc, char** argv) {people* p_map;char temp = 'a';int fd = open(argv[1], O_CREAT|O_RDWR|O_TRUNC, 00777);if (-1 == fd){printf("open file error = %s\n", strerror(errno));return -1;}ftruncate(fd, sizeof(people)*10);p_map = (people*)mmap(NULL, sizeof(people)*10, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if (MAP_FAILED == p_map){printf("mmap file error = %s\n", strerror(errno));return -1;}for(int i = 0; i < 10; i++){memcpy( ( *(p_map+i) ).name, &temp, 1);( *(p_map+i) ).name[1] = 0;( *(p_map+i) ).age = 20+i;temp += 1;}printf("initialize over\n");close(fd);munmap(p_map, sizeof(people)*10);printf("umap ok \n");return 0; }讀共享內(nèi)存
#include <fcntl.h> #include <sys/mman.h> #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/stat.h>typedef struct {char name[32];int age; } people;main(int argc, char** argv) {people* p_map;struct stat filestat;int fd = open(argv[1], O_CREAT|O_RDWR, 00777);if (-1 == fd){printf("open file error = %s\n", strerror(errno));return -1;}fstat(fd, &filestat);p_map = (people*)mmap(NULL, filestat.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if (MAP_FAILED == p_map){printf("mmap file error = %s\n", strerror(errno));return -1;}for(int i = 0; i < 10; i++){printf("name = %s, age = %d\n",(*(p_map+i)).name, (*(p_map+i)).age);}close(fd);munmap(p_map, sizeof(people)*10);printf("umap ok \n");return 0; }結(jié)果說明
[root@rocket ipc]# g++ -g -o ipc_mmap_writer ipc_mmap_writer.cpp
[root@rocket ipc]# ./ipc_mmap_writer /tmp/mmap_text.file
initialize over
umap ok
[root@rocket ipc]# g++ -g -o ipc_mmap_reader ipc_mmap_reader.cpp
[root@rocket ipc]# ./ipc_mmap_reader /tmp/mmap_text.file
name = a, age = 20
name = b, age = 21
name = c, age = 22
name = d, age = 23
name = e, age = 24
name = f, age = 25
name = g, age = 26
name = h, age = 27
name = i, age = 28
name = j, age = 29
umap ok
查看mmap文件
[root@rocket ipc]# ll /tmp/mmap_text.file
-rwxr-xr-x. 1 root root 360 Oct 14 02:55 /tmp/mmap_text.file
POSIX共享內(nèi)存
POSIX共享內(nèi)存使用方法有以下兩個步驟:
?? 通過shm_open創(chuàng)建或打開一個POSIX共享內(nèi)存對象
?? 調(diào)用mmap將它映射到當(dāng)前進程的地址空間
和通過內(nèi)存映射文件進行通信的使用上差別在于mmap描述符參數(shù)獲取方式不一樣:通過open或shm_open。如下圖所示:
圖6:Posix內(nèi)存映射文件
POSIX共享內(nèi)存和POSIX消息隊列,有名信號量一樣都是具有隨內(nèi)核持續(xù)性的特點。
在Linux 2.6.x中,對于POSIX信號量和共享內(nèi)存的名字會在/dev/shm下建立對應(yīng)的路徑名
[root@rocket shm]# ll /dev/shm/|grep mem
-rwxr-xr-x. 1 root root????? 360 Oct 14 05:23 shm_from_mem.txt
函數(shù)說明
#include <sys/mman.h>
#include <sys/stat.h>??????? /* For mode constants */
#include <fcntl.h>? ???????? /* For O_* constants */
// 打開一個共享內(nèi)存的文件句柄
int shm_open(const char *name, int oflag, mode_t mode);
注意這里的名字具有形式 /somename,即必須以 / 為開頭,因為POSIX共享內(nèi)存對應(yīng)的文件是位于/dev/shm這個特殊的文件系統(tǒng)內(nèi)。
?
// 刪除一個共享內(nèi)存的名字,但只有所有程序都關(guān)閉,才會真的刪除
int shm_unlink(const char *name);
代碼說明
寫共享內(nèi)存
#include <sys/mman.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h>typedef struct {char name[32];int age; } people;main(int argc, char** argv) {people* p_map;char temp = 'a';int fd = shm_open(argv[1], O_CREAT|O_RDWR, 00777);if (-1 == fd){printf("open file error = %s\n", strerror(errno));return -1;}ftruncate(fd, sizeof(people)*10);p_map = (people*)mmap(NULL, sizeof(people)*10, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if (MAP_FAILED == p_map){printf("mmap file error = %s\n", strerror(errno));return -1;}for(int i = 0; i < 10; i++){memcpy( ( *(p_map+i) ).name, &temp, 1);( *(p_map+i) ).name[1] = 0;( *(p_map+i) ).age = 20+i;temp += 1;}printf("initialize over\n");close(fd);munmap(p_map, sizeof(people)*10);printf("umap ok \n");return 0; }讀共享內(nèi)存
?
#include <fcntl.h> #include <sys/mman.h> #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/stat.h>typedef struct {char name[32];int age; } people;main(int argc, char** argv) {people* p_map;struct stat filestat;int fd = shm_open(argv[1], O_CREAT|O_RDWR, 00777);if (-1 == fd){printf("open file error = %s\n", strerror(errno));return -1;}fstat(fd, &filestat);p_map = (people*)mmap(NULL, filestat.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if (MAP_FAILED == p_map){printf("mmap file error = %s\n", strerror(errno));return -1;}for(int i = 0; i < 10; i++){printf("name = %s, age = %d\n",(*(p_map+i)).name, (*(p_map+i)).age);}close(fd);munmap(p_map, sizeof(people)*10);printf("umap ok \n");return 0; }刪除共享內(nèi)存
#include <fcntl.h> #include <sys/mman.h> #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/stat.h>main(int argc, char** argv) {int ret = shm_unlink(argv[1]);if (-1 == ret){printf("unlink shm error = %s\n", strerror(errno));return -1;}printf("unlink ok \n");return 0; }結(jié)果說明
[root@rocket ipc]# g++ -g -o ipc_posix_mmap_writer ipc_posix_mmap_writer.cpp -lrt
[root@rocket ipc]# ./ipc_posix_mmap_writer /shm_from_mem.txt
initialize over
umap ok
[root@rocket ipc]# g++ -g -o ipc_posix_mmap_reader ipc_posix_mmap_reader.cpp -lrt
[root@rocket ipc]# ./ipc_posix_mmap_reader /shm_from_mem.txt
name = a, age = 20
name = b, age = 21
name = c, age = 22
name = d, age = 23
name = e, age = 24
name = f, age = 25
name = g, age = 26
name = h, age = 27
name = i, age = 28
name = j, age = 29
umap ok
?
[root@rocket ipc]# ./ipc_posix_mmap_unlink /shm_from_mem.txt
unlink ok
[root@rocket ipc]# ./ipc_posix_mmap_unlink /shm_from_mem.txt
unlink shm error = No such file or directory
[root@rocket ipc]# ll /dev/shm/|grep mem
[root@rocket ipc]#
可以看到/dev/shm下面的shm_from_mem.txt已經(jīng)被刪除了。
System V共享內(nèi)存
系統(tǒng)調(diào)用mmap()通過映射一個普通文件實現(xiàn)共享內(nèi)存。System V則是通過映射特殊文件系統(tǒng)shm中的文件實現(xiàn)進程間的共享內(nèi)存通信。也就是說,每個共享內(nèi)存區(qū)域?qū)?yīng)特殊文件系統(tǒng)shm中的一個文件(這是通過shmid_kernel結(jié)構(gòu)聯(lián)系起來的)。進程間需要共享的數(shù)據(jù)被放在一個叫做IPC共享內(nèi)存區(qū)域的地方,所有需要訪問該共享區(qū)域的進程都要把該共享區(qū)域映射到本進程的地址空間中去。System V共享內(nèi)存通過shmget獲得或創(chuàng)建一個IPC共享內(nèi)存區(qū)域,并返回相應(yīng)的標(biāo)識符。內(nèi)核在保證shmget獲得或創(chuàng)建一個共享內(nèi)存區(qū),初始化該共享內(nèi)存區(qū)相應(yīng)的shmid_kernel結(jié)構(gòu)注同時,還將在特殊文件系統(tǒng)shm中,創(chuàng)建并打開一個同名文件,并在內(nèi)存中建立起該文件的相應(yīng)dentry及inode結(jié)構(gòu),新打開的文件不屬于任何一個進程(任何進程都可以訪問該共享內(nèi)存區(qū))。所有這一切都是系統(tǒng)調(diào)用shmget完成的。
每一個共享內(nèi)存區(qū)都有一個控制結(jié)構(gòu)struct shmid_kernel,shmid_kernel是共享內(nèi)存區(qū)域中非常重要的一個數(shù)據(jù)結(jié)構(gòu),它是存儲管理和文件系統(tǒng)結(jié)合起來的橋梁,定義如下:
struct shmid_kernel /* private to the kernel */
{???????
???????? struct kern_ipc_perm????? shm_perm;
???????? struct file *??????????????? shm_file;
???????? int?????????????????????? id;
???????? unsigned long?????????? shm_nattch;
???????? unsigned long?????????? shm_segsz;
???????? time_t???????????????????????? shm_atim;
???????? time_t???????????????????????? shm_dtim;
???????? time_t???????????????????????? shm_ctim;
???????? pid_t??????????????????????????? shm_cprid;
???????? pid_t??????????????????????????? shm_lprid;
};
該結(jié)構(gòu)中最重要的一個域應(yīng)該是shm_file,它存儲了將被映射文件的地址。每個共享內(nèi)存區(qū)對象都對應(yīng)特殊文件系統(tǒng)shm中的一個文件,一般情況下,特殊文件系統(tǒng)shm中的文件是不能用read()、write()等方法訪問的,當(dāng)采取共享內(nèi)存的方式把其中的文件映射到進程地址空間后,可直接采用訪問內(nèi)存的方式對其訪問。
圖7:System V共享內(nèi)存內(nèi)核結(jié)構(gòu)
內(nèi)核通過數(shù)據(jù)結(jié)構(gòu)struct ipc_ids shm_ids維護系統(tǒng)中的所有共享內(nèi)存區(qū)域。上圖中的shm_ids.entries變量指向一個ipc_id結(jié)構(gòu)數(shù)組,而每個ipc_id結(jié)構(gòu)數(shù)組中有個指向kern_ipc_perm結(jié)構(gòu)的指針。到這里讀者應(yīng)該很熟悉了,對于系統(tǒng)V共享內(nèi)存區(qū)來說,kern_ipc_perm的宿主是shmid_kernel結(jié)構(gòu),shmid_kernel是用來描述一個共享內(nèi)存區(qū)域的,這樣內(nèi)核就能夠控制系統(tǒng)中所有的共享區(qū)域。同時,在shmid_kernel結(jié)構(gòu)的file類型指針shm_file指向文件系統(tǒng)shm中相應(yīng)的文件,這樣,共享內(nèi)存區(qū)域就與shm文件系統(tǒng)中的文件對應(yīng)起來。
在創(chuàng)建了一個共享內(nèi)存區(qū)域后,還要將它映射到進程地址空間,系統(tǒng)調(diào)用shmat()完成此項功能。由于在調(diào)用shmget()時,已經(jīng)創(chuàng)建了文件系統(tǒng)shm中的一個同名文件與共享內(nèi)存區(qū)域相對應(yīng),因此,調(diào)用shmat()的過程相當(dāng)于映射文件系統(tǒng)shm中的同名文件過程,原理與mmap()大同小異。
函數(shù)說明
#include <sys/ipc.h>
#include <sys/shm.h>
// 獲取共享內(nèi)存區(qū)域
int shmget(key_t key, size_t size, int shmflg);
// 連接共享內(nèi)存區(qū)域
void *shmat(int shmid, const void *shmaddr, int shmflg);
// 斷開共享內(nèi)存區(qū)域
int shmdt(const void *shmaddr);
// 對共享內(nèi)存區(qū)域進行控制
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
// 將path和proj_id轉(zhuǎn)換成System V IPC key
key_t ftok(const char *pathname, int proj_id);
代碼說明
寫共享內(nèi)存
#include <sys/mman.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/ipc.h> #include <sys/shm.h>typedef struct {char name[32];int age; } people;int main(int argc, char** argv) {int shm_id,i;key_t key;people* p_map;char temp = 'a';const char* name = "/dev/shm/my_systemv_shm1";key = ftok(name,0);if (key == -1){perror("ftok error");return -1;}shm_id=shmget(key, 4096, IPC_CREAT);if(shm_id == -1){perror("shmget error");return -1;}p_map=(people*)shmat(shm_id,NULL,0);for(int i = 0; i < 10; i++){memcpy( ( *(p_map+i) ).name, &temp, 1);( *(p_map+i) ).name[1] = 0;( *(p_map+i) ).age = 20+i;temp += 1;}printf("initialize over\n");if(shmdt(p_map) == -1){perror(" detach error ");return -1;}return 0; }讀共享內(nèi)存
#include <sys/mman.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/ipc.h> #include <sys/shm.h>typedef struct {char name[32];int age; } people;int main(int argc, char** argv) {int shm_id,i;key_t key;people* p_map;const char* name = "/dev/shm/my_systemv_shm1";key = ftok(name,0);if (key == -1){perror("ftok error");return -1;}shm_id=shmget(key, 4096, IPC_CREAT);if(shm_id == -1){perror("shmget error");return -1;}p_map=(people*)shmat(shm_id,NULL,0);for(int i = 0; i < 10; i++){printf( "name:%s, ",(*(p_map+i)).name );printf( "age %d\n",(*(p_map+i)).age );}if(shmdt(p_map) == -1){perror(" detach error ");return -1;}return 0; }結(jié)果說明
[root@rocket ipc]# g++ -g -o ipc_systemv_mmap_writer ipc_systemv_mmap_writer.cpp
[root@rocket ipc]# touch /dev/shm/my_systemv_shm1
[root@rocket ipc]# ./ipc_systemv_mmap_writer
initialize over
[root@rocket ipc]# g++ -g -o ipc_systemv_mmap_reader ipc_systemv_mmap_reader.cpp
[root@rocket ipc]# ./ipc_systemv_mmap_reader
name:a, age 20
name:b, age 21
name:c, age 22
name:d, age 23
name:e, age 24
name:f, age 25
name:g, age 26
name:h, age 27
name:i, age 28
name:j, age 29
?
觀察一下共享內(nèi)存:
[root@rocket ipc]# ./get_ipc_key /dev/shm/my_systemv_shm1
key = 1084739
[root@rocket ipc]# ipcs
?
------ Shared Memory Segments --------
key??????? shmid????? owner????? perms????? bytes????? nattch???? status?????
0x00000000 0????????? gdm??????? 600??????? 393216???? 2????????? dest????????
0x00000000 32769????? gdm??????? 600??????? 393216???? 2????????? dest? ??????
0x00000000 65538????? gdm??????? 600??????? 393216???? 2????????? dest????????
0x00000000 98307????? gdm??????? 600??????? 393216???? 2????????? dest????????
0x00108d43 131076???? root?????? 0????????? 4096?????? 0 ??
?
看到我們新建的共享內(nèi)存了吧?刪除也很簡單:
[root@rocket ipc]# ipcrm -m 131076
[root@rocket ipc]# ipcs
?
------ Shared Memory Segments --------
key??????? shmid????? owner????? perms????? bytes????? nattch???? status?????
0x00000000 0????????? gdm??????? 600??????? 393216???? 2????????? dest????????
0x00000000 32769????? gdm??????? 600??????? 393216???? 2????????? dest????????
0x00000000 65538????? gdm??????? 600??????? 393216???? 2????????? dest????????
0x00000000 98307????? gdm??????? 600??????? 393216???? 2????????? dest
?
總結(jié)及3種共享內(nèi)存比較
共享內(nèi)存是最快的IPC形式,在開發(fā)中,我們一定要充分利用好共享內(nèi)存的特性,取得事半功倍的效果。
| 類型 | 原理 | 易失性 |
| mmap | 利用文件(open)映射共享內(nèi)存區(qū)域 | 會保存在磁盤上,不會丟失 |
| Posix shared memory | 利用/dev/shm文件系統(tǒng)(mmap)映射共享內(nèi)存區(qū)域 | 隨內(nèi)核持續(xù),內(nèi)核自舉后會丟失 |
| SystemV shared memory | 利用/dev/shm文件系統(tǒng)(shmat)映射共享內(nèi)存區(qū)域 | 隨內(nèi)核持續(xù),內(nèi)核自舉后會丟失 |
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/linuxbug/p/4882776.html
總結(jié)
以上是生活随笔為你收集整理的Linux进程间通信(四) - 共享内存的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Digital System Desig
- 下一篇: linux系统在虚拟机中迁移的技术难点