深入學(xué)習(xí)C語(yǔ)言mmap和shm*的使用方法技巧
一、背景
共享內(nèi)存使用場(chǎng)景:當(dāng)有一個(gè)超大的文件,如何能快速的讀寫?
文件是存儲(chǔ)在磁盤上的,要快速的讀寫一個(gè)大文件,可以通過(guò)共享內(nèi)存的方式(mmap等)。mmap內(nèi)部是使用的DMA技術(shù),DMA是內(nèi)存和磁盤之間的傳輸方式,有自己的指令,不需要CPU的參與。
零拷貝技術(shù):我們常說(shuō)的拷貝,是需要CPU參與的,通過(guò)CPU指令將文件內(nèi)容復(fù)制一份到內(nèi)存中。所謂的零拷貝,就是不需要CPU的參與,而不是其他的意思。零拷貝有mmap和shm*接口這些方式實(shí)現(xiàn)。
二、內(nèi)存映射mmap
應(yīng)用程序和內(nèi)核或磁盤直接數(shù)據(jù)交互,可以通過(guò)映射內(nèi)存塊的方式。
mmap():將文件或設(shè)備映射到內(nèi)存。
munmap():將文件或設(shè)備取消映射到內(nèi)存。
函數(shù)原型:
#include <sys/mman.h> void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); int munmap(void *addr, size_t length);
mmap的內(nèi)存即不在堆也不在棧上,是一塊獨(dú)立的空間。
2.1、mmap()
mmap()在調(diào)用進(jìn)程的虛擬地址空間中創(chuàng)建一個(gè)新的映射。新映射的起始地址在addr中指定。length參數(shù)指定映射的長(zhǎng)度。
如果addr為空,則內(nèi)核選擇創(chuàng)建映射的地址;這是創(chuàng)建新映射的最可移植方法。 如果addr不為空,則內(nèi)核將其作為一個(gè)提示,提示將映射放置在何處;在Linux上,映射將在附近的頁(yè)面邊界處創(chuàng)建。新映射的地址作為調(diào)用的結(jié)果返回。
文件映射的內(nèi)容(與匿名映射相反;參見下面的MAP_MAP_ANONYMOUS)使用文件描述符fd所引用的文件(或其他對(duì)象)中從偏移量offset開始的length字節(jié)進(jìn)行初始化。offset必須是sysconf(_SC_PAGE_SIZE)返回的頁(yè)面大小的倍數(shù)。
prot參數(shù)描述了映射所需的內(nèi)存保護(hù)(不得與文件的打開模式?jīng)_突)。它是PROT_NONE或以下一個(gè)或多個(gè)標(biāo)志的位OR:
標(biāo)志 | 含義 |
---|---|
PROT_EXEC | 可以執(zhí)行頁(yè)面。 |
PROT_READ | 可以讀取頁(yè)面。 |
PROT_WRITE | 可以寫入頁(yè)面。 |
PROT_NONE | 可能無(wú)法訪問(wèn)頁(yè)面。 |
flags參數(shù)確定映射的更新是否對(duì)映射相同區(qū)域的其他進(jìn)程可見,以及更新是否傳遞到基礎(chǔ)文件。通過(guò)在標(biāo)志中包含以下值中的一個(gè)來(lái)確定此行為:
標(biāo)志 | 含義 |
---|---|
MAP_SHARED | 共享此映射。對(duì)映射的更新對(duì)映射此文件的其他進(jìn)程可見,并會(huì)傳遞到基礎(chǔ)文件。(要精確控制對(duì)底層文件進(jìn)行更新的時(shí)間,需要使用msync()) |
MAP_PRIVATE | 創(chuàng)建寫時(shí)私有副本映射。映射的更新對(duì)于映射同一文件的其他進(jìn)程不可見,并且不會(huì)傳遞到基礎(chǔ)文件。未指定在mmap()調(diào)用后對(duì)文件所做的更改是否在映射區(qū)域中可見。 |
此外,以下值中的零個(gè)或多個(gè)可以在flag中進(jìn)行“或”運(yùn)算:
標(biāo)志 | 含義 |
---|---|
MAP_32B5IT | (自Linux 2.4.20、2.6起)將映射放入進(jìn)程地址空間的前2千兆字節(jié)。對(duì)于64位程序,此標(biāo)志僅在x86-64上受支持。添加它是為了允許在第一個(gè)2GB內(nèi)存中的某個(gè)位置分配線程堆棧,從而提高早期64位處理器上的上下文切換性能?,F(xiàn)代x86-64處理器不再存在此性能問(wèn)題,因此在這些系統(tǒng)上不需要使用此標(biāo)志。當(dāng)設(shè)置MAP_ FIXED時(shí),MAP_32BIT標(biāo)志被忽略。 |
MAP_ANON | MAP_ANONYMOUS的同義詞。不贊成。 |
MAP_ANONYMOUS | 映射沒(méi)有任何文件支持;其內(nèi)容被初始化為零。忽略fd和offset參數(shù);然而,如果指定了MAP_ANONYMOUS(或MAP_ANON),則某些實(shí)現(xiàn)要求fd為-1,可移植應(yīng)用程序應(yīng)確保這一點(diǎn)。只有從內(nèi)核2.4開始,Linux才支持將MAP_ANONYMOUS與MAP_SHARED結(jié)合使用。 |
MAP_DENYWRITE | 忽略此標(biāo)志。(很久以前,它發(fā)出了一個(gè)信號(hào),表示嘗試寫入底層文件時(shí),ETXTBUSY會(huì)失敗。但這是拒絕服務(wù)攻擊的一個(gè)來(lái)源。) |
MAP_EXECUTABLE | 忽略此標(biāo)志。 |
MAP_FILE | 兼容性標(biāo)志。忽略。 |
… | … |
返回值:成功后,mmap()返回指向映射區(qū)域的指針。錯(cuò)誤時(shí),返回值MAP_FAILED(即,(void*)-1),并設(shè)置errno以指示錯(cuò)誤原因。
2.2、munmap()
munmap()系統(tǒng)調(diào)用刪除指定地址范圍的映射,并導(dǎo)致對(duì)該范圍內(nèi)地址的進(jìn)一步引用生成無(wú)效內(nèi)存引用。當(dāng)進(jìn)程終止時(shí),區(qū)域也會(huì)自動(dòng)取消映射。另一方面,關(guān)閉文件描述符不會(huì)取消區(qū)域映射。
地址addr必須是頁(yè)面大小的倍數(shù)(但長(zhǎng)度不必是)。包含指定范圍一部分的所有頁(yè)面均未映射,對(duì)這些頁(yè)面的后續(xù)引用將生成SIGSEGV。如果指示的范圍不包含任何映射頁(yè),則不是錯(cuò)誤。
返回值:成功時(shí),munmap()返回0。失敗時(shí),它返回-1,errno被設(shè)置為指示錯(cuò)誤原因(可能是EINVAL)。
錯(cuò)誤代碼
錯(cuò)誤代碼 | 含義 |
---|---|
EACCES | 文件描述符指的是非常規(guī)文件。或者請(qǐng)求了文件映射,但fd未打開讀取?;蛘哒?qǐng)求MAP_SHARED并且設(shè)置PROT_WRITE,但fd在讀/寫(O_RDWR)模式下未打開?;蛘咴O(shè)置了PROT_WRITE,但該文件僅為append。 |
EAGAIN | 文件已鎖定,或已鎖定過(guò)多內(nèi)存【請(qǐng)參閱setrlimit()】。 |
EBADF | fd不是有效的文件描述符(并且未設(shè)置MAP_ANONYMOUS)。 |
EINVAL | 我們不喜歡addr、length或offset(例如,它們太大,或者在頁(yè)面邊界上沒(méi)有對(duì)齊)。(自Linux 2.6.12起)length為0。 |
EINVAL | 標(biāo)志既不包含MAP_PRIVATE也不包含MAP_SHARED,或者同時(shí)包含這兩個(gè)值。 |
ENFILE | 已達(dá)到系統(tǒng)范圍內(nèi)打開文件總數(shù)的限制。 |
ENODEV | 指定文件的底層文件系統(tǒng)不支持內(nèi)存映射。 |
ENOMEM | 沒(méi)有可用的內(nèi)存。 |
ENOMEM | 進(jìn)程的最大映射數(shù)將被超過(guò)。當(dāng)在現(xiàn)有映射的中間取消映射區(qū)域時(shí),munmap()也會(huì)出現(xiàn)此錯(cuò)誤,因?yàn)檫@會(huì)導(dǎo)致在未映射區(qū)域的任一側(cè)出現(xiàn)兩個(gè)較小的映射。 |
EPERM | prot參數(shù)要求PORT_EXEC,但映射區(qū)域?qū)儆谖窗惭bEXEC的文件系統(tǒng)上的文件。 |
EPERM | 文件封條阻止了該操作;見fcntl()。 |
ETXTBSY | MAP_DENYWRITE已設(shè)置,但fd指定的對(duì)象已打開寫入。 |
EOVERFLOW | 在32位體系結(jié)構(gòu)和大文件擴(kuò)展名(即使用64位off_t)上:用于長(zhǎng)度的頁(yè)數(shù)加上用于偏移量的頁(yè)數(shù)將溢出無(wú)符號(hào)長(zhǎng)(32位)。 |
使用映射區(qū)域可產(chǎn)生以下信號(hào):
信號(hào) | 含義 |
---|---|
SIGSEGV | 試圖寫入映射為只讀的區(qū)域。 |
SIGBUS | 試圖訪問(wèn)緩沖區(qū)中與文件不對(duì)應(yīng)的部分(例如,超出文件末尾,包括另一個(gè)進(jìn)程截?cái)辔募那闆r)。 |
2.3、流程
(1)打開文件
(2)取文件大小
(3)把文件映射成虛擬內(nèi)存
(4)通過(guò)對(duì)內(nèi)存的讀寫來(lái)實(shí)現(xiàn)對(duì)文件的讀寫
(5)卸載映射
(6)關(guān)閉文件
2.4、示例代碼
#include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) int main(int argc, char *argv[]) { char *addr; int fd; struct stat sb; off_t offset, pa_offset; size_t length; ssize_t s; if (argc < 3 || argc > 4) { fprintf(stderr, "%s file offset [length]\n", argv[0]); exit(EXIT_FAILURE); } fd = open(argv[1], O_RDONLY); if (fd == -1) handle_error("open"); if (fstat(fd, &sb) == -1) /* To obtain file size */ handle_error("fstat"); offset = atoi(argv[2]); pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1); /* offset for mmap() must be page aligned */ if (offset >= sb.st_size) { fprintf(stderr, "offset is past end of file\n"); exit(EXIT_FAILURE); } if (argc == 4) { length = atoi(argv[3]); if (offset + length > sb.st_size) length = sb.st_size - offset; /* Can't display bytes past end of file */ } else { /* No length arg ==> display to end of file */ length = sb.st_size - offset; } addr = mmap(NULL, length + offset - pa_offset, PROT_READ, MAP_PRIVATE, fd, pa_offset); if (addr == MAP_FAILED) handle_error("mmap"); s = write(STDOUT_FILENO, addr + offset - pa_offset, length); if (s != length) { if (s == -1) handle_error("write"); fprintf(stderr, "partial write"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
三、shm*接口
共享內(nèi)存就是允許兩個(gè)不相關(guān)的進(jìn)程訪問(wèn)同一個(gè)內(nèi)存塊。共享內(nèi)存是在兩個(gè)正在運(yùn)行的進(jìn)程之間共享和傳遞數(shù)據(jù)的一種非常有效的方式。進(jìn)程可以將同一段共享內(nèi)存連接到它們自己的地址空間中,所有進(jìn)程都可以訪問(wèn)共享內(nèi)存中的地址。而如果某個(gè)進(jìn)程向共享內(nèi)存寫入數(shù)據(jù),所做的改動(dòng)將立即影響到可以訪問(wèn)同一段共享內(nèi)存的任何其他進(jìn)程。
共享內(nèi)存并未提供同步機(jī)制,也就是說(shuō),在第一個(gè)進(jìn)程結(jié)束對(duì)共享內(nèi)存的寫操作之前,并無(wú)自動(dòng)機(jī)制可以阻止第二個(gè)進(jìn)程開始對(duì)它進(jìn)行讀取。所以,通常需要用其他的機(jī)制來(lái)同步對(duì)共享內(nèi)存的訪問(wèn),例如信號(hào)量。
3.1、shmget()
創(chuàng)建共享內(nèi)存。函數(shù)原型:
#include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, size_t size, int shmflg);
描述:shmget()返回與參數(shù)key的值關(guān)聯(lián)的System V共享內(nèi)存段的標(biāo)識(shí)符。如果key的值為IPC_PRIVATE或key不是IPC_PRIVATE,不存在與key對(duì)應(yīng)的共享內(nèi)存段,并且在shmflg中指定了IPC_CREAT,則會(huì)創(chuàng)建一個(gè)大小等于size值的新共享內(nèi)存段(向上舍入為PAGE_SIZE的倍數(shù))。
如果shmflg同時(shí)指定IPC_CREAT和IPC_ EXCL,并且key已經(jīng)存在共享內(nèi)存段,則shmget()將失敗,錯(cuò)誤號(hào)設(shè)置為EEXIST?!具@類似于open()的組合O_CREAT|O_EXCL的效果?!?/p>
值shmflg由以下組成:
標(biāo)志 | 含義 |
---|---|
IPC_CREAT | 創(chuàng)建新段。如果未使用此標(biāo)志,則shmget()將查找與鍵關(guān)聯(lián)的段,并檢查用戶是否有訪問(wèn)該段的權(quán)限。 |
IPC_EXCL | 此標(biāo)志與IPC_ CREAT一起使用,以確保此調(diào)用創(chuàng)建段。如果段已經(jīng)存在,則調(diào)用失敗。 |
SHM_HUGETLB | (自Linux 2.6起)使用“巨大頁(yè)面”分配段。 |
SHM_HUGE_2MB、SHM_ HUGE _1GB | (自Linux 3.8起)與SHM_HUGETLB結(jié)合使用,在支持多種HUGETLB頁(yè)面大小的系統(tǒng)上選擇可選的HUGETLB頁(yè)大?。ǚ謩e為2 MB和1 GB)。更一般地,可以通過(guò)在偏移SHM_SHAGE_SHIFT處對(duì)六位中的期望頁(yè)面大小的以2為底的對(duì)數(shù)進(jìn)行編碼來(lái)配置期望的巨大頁(yè)面大小。因此,上述兩個(gè)常數(shù)定義為:#define SHM_HUGE_2MB (21 << SHM_HUGE_SHIFT) 和 #define SHM_HUGE_1GB (30 << SHM_HUGE_SHIFT) |
SHM_NORESERVE | (自Linux 2.6.15起)該標(biāo)志的作用與mmap() MAP_NORESERVE標(biāo)志相同。不要為此段保留交換空間。當(dāng)保留交換空間時(shí),可以保證可以修改段。當(dāng)交換空間未保留時(shí),如果沒(méi)有可用的物理內(nèi)存,則在寫入時(shí)可能會(huì)得到SIGSEGV。 |
除上述標(biāo)志外,shmflg的最低有效9位指定授予所有者、組和其他人的權(quán)限。這些位的格式和含義與open()的模式參數(shù)相同。目前,系統(tǒng)不使用執(zhí)行權(quán)限。
返回值:成功后,將返回有效的共享內(nèi)存標(biāo)識(shí)符。出現(xiàn)錯(cuò)誤時(shí),返回-1,并設(shè)置errno以指示錯(cuò)誤。
錯(cuò)誤:失敗時(shí),錯(cuò)誤號(hào)設(shè)置為以下之一:
錯(cuò)誤代碼 | 含義 |
---|---|
EACCES | 用戶沒(méi)有訪問(wèn)共享內(nèi)存段的權(quán)限,并且沒(méi)有CAP_IPC_OWNER功能。 |
EEXIST | 在shmflg中指定了IPC_CREAT和IPC_ EXCL,但密鑰的共享內(nèi)存段已經(jīng)存在。 |
EINVAL | 將創(chuàng)建一個(gè)新的段,其大小小于SHMMIN或大于SHMMAX。 |
EINVAL | 給定鍵的段存在,但大小大于該段的大小。 |
ENFILE | 已達(dá)到系統(tǒng)范圍內(nèi)打開文件總數(shù)的限制。 |
ENOENT | 給定密鑰不存在任何段,并且未指定IPC_CREAT。 |
ENOMEM | 無(wú)法為段開銷分配內(nèi)存。 |
ENOSPC | 已獲取所有可能的共享內(nèi)存ID(SHMMNI),或者分配請(qǐng)求大小的段將導(dǎo)致系統(tǒng)超過(guò)系統(tǒng)范圍內(nèi)的限制共享內(nèi)存(SHMALL)。 |
EPERM | 指定了SHM_HUGETLB標(biāo)志,但調(diào)用方?jīng)]有特權(quán)(沒(méi)有CAP_IPC_LOCK功能)。 |
3.2、shmat()
啟動(dòng)對(duì)該共享內(nèi)存的訪問(wèn),并把共享內(nèi)存連接到當(dāng)前進(jìn)程的地址空間,函數(shù)原型:
#include <sys/types.h> #include <sys/shm.h> void *shmat(int shmid, const void *shmaddr, int shmflg);
描述:shmat()將由shmid標(biāo)識(shí)的System V共享內(nèi)存段附加到調(diào)用進(jìn)程的地址空間。附加地址由shmaddr根據(jù)以下標(biāo)準(zhǔn)之一指定:
(1)如果shmaddr為空,系統(tǒng)將選擇一個(gè)合適的(未使用的)地址來(lái)連接段。
(2)如果shmaddr不為空,并且在shmflg中指定了SHM_RND,則附加發(fā)生在等于shmaddr的地址處,向下舍入到SHMLBA的最近倍數(shù)。
(3)否則,shmaddr必須是發(fā)生附加的頁(yè)對(duì)齊地址。
除了SHM_RND,還可以在shmflg位掩碼參數(shù)中指定以下標(biāo)志:
標(biāo)志 | 含義 |
---|---|
SHM_EXEC | (特定于Linux;自Linux 2.6.9起)允許執(zhí)行段的內(nèi)容。調(diào)用者必須對(duì)段具有執(zhí)行權(quán)限。 |
SHM_RDONLY | 附加段以進(jìn)行只讀訪問(wèn)。進(jìn)程必須具有段的讀取權(quán)限。如果未指定此標(biāo)志,則附加該段以進(jìn)行讀寫訪問(wèn),并且進(jìn)程必須具有該段的讀寫權(quán)限。不存在只寫共享內(nèi)存段的概念。 |
SHM_REMAP | (特定于Linux)此標(biāo)志指定線段的映射應(yīng)替換范圍內(nèi)從shmaddr開始并持續(xù)到線段大小的任何現(xiàn)有映射。(通常,如果此地址范圍中已存在映射,則會(huì)導(dǎo)致EINVAL錯(cuò)誤。)在這種情況下,shmaddr不能為空。 |
呼叫進(jìn)程的brk()值不被附加改變。該段將在進(jìn)程退出時(shí)自動(dòng)分離。同一段可以作為讀寫段附加在進(jìn)程的地址空間中,并且可以多次附加。
成功的shmat()調(diào)用更新與共享內(nèi)存段相關(guān)聯(lián)的shmid_ds結(jié)構(gòu)的成員【參見shmctl()】,如下所示:
shm_ atime被設(shè)置為當(dāng)前時(shí)間。
shm_ lpid被設(shè)置為調(diào)用進(jìn)程的進(jìn)程ID。
shm_natch遞增1。
返回值:成功時(shí),shmat()返回附加共享內(nèi)存段的地址;錯(cuò)誤時(shí),返回(void*)-1,并設(shè)置errno以指示錯(cuò)誤原因。
錯(cuò)誤:當(dāng)shmat()失敗時(shí),errno設(shè)置為以下之一:
錯(cuò)誤代碼 | 含義 |
---|---|
EACCES | 調(diào)用進(jìn)程不具有請(qǐng)求的附加類型所需的權(quán)限,并且不具有CAP_IPC_OWNER功能。 |
EIDRM | shmid指向已刪除的標(biāo)識(shí)符。 |
EINVAL | 無(wú)效的shmid值,未對(duì)齊(即,未頁(yè)面對(duì)齊且未指定SHM_RND)或無(wú)效的shmaddr值,或無(wú)法在shmaddr處附加段,或指定了SHM_ REMAP且shmaddr為空。 |
ENOMEM | 無(wú)法為描述符或頁(yè)表分配內(nèi)存。 |
3.3、shmdt()
將共享內(nèi)存從當(dāng)前進(jìn)程中分離。注意,將共享內(nèi)存分離并不是刪除它,只是使該共享內(nèi)存對(duì)當(dāng)前進(jìn)程不再可用。函數(shù)原型:
#include <sys/types.h> #include <sys/shm.h> int shmdt(const void *shmaddr);
描述:shmdt()將位于shmaddr指定地址的共享內(nèi)存段從調(diào)用進(jìn)程的地址空間中分離。要分離的段當(dāng)前附加的shmaddr必須等于附加的shmat()調(diào)用返回的值。
參數(shù)shmaddr是shmat()函數(shù)返回的地址指針。
在成功調(diào)用shmdt()時(shí),系統(tǒng)更新與共享內(nèi)存段關(guān)聯(lián)的shmid_ds結(jié)構(gòu)的成員,如下所示:
shm_ atime被設(shè)置為當(dāng)前時(shí)間。
shm_ lpid被設(shè)置為調(diào)用進(jìn)程的進(jìn)程ID。
shm_natch減1。
返回值:成功時(shí),shmdt()返回0;在出現(xiàn)錯(cuò)誤時(shí),返回-1,并設(shè)置errno以指示錯(cuò)誤原因。
錯(cuò)誤:當(dāng)shmdt()失敗時(shí),errno設(shè)置如下:
錯(cuò)誤代碼 | 含義 |
---|---|
EINVAL | 在shmaddr沒(méi)有附加共享內(nèi)存段;或者,shmaddr不在頁(yè)面邊界上對(duì)齊。 |
3.4、shmctl()
控制共享內(nèi)存。函數(shù)原型:
#include <sys/ipc.h> #include <sys/shm.h> int shmctl(int shmid, int cmd, struct shmid_ds *buf);
描述:shmctl()對(duì)系統(tǒng)V共享內(nèi)存段執(zhí)行cmd指定的控制操作,該段的標(biāo)識(shí)符在shmid中給出。
buf參數(shù)是指向shmid_ds結(jié)構(gòu)的指針,如下:
struct shmid_ds { struct ipc_perm shm_perm; /* Ownership and permissions */ size_t shm_segsz; /* Size of segment (bytes) */ time_t shm_atime; /* Last attach time */ time_t shm_dtime; /* Last detach time */ time_t shm_ctime; /* Last change time */ pid_t shm_cpid; /* PID of creator */ pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */ shmatt_t shm_nattch; /* No. of current attaches */ ... };
ipc_perm結(jié)構(gòu)定義如下:
struct ipc_perm { key_t __key; /* Key supplied to shmget(2) */ uid_t uid; /* Effective UID of owner */ gid_t gid; /* Effective GID of owner */ uid_t cuid; /* Effective UID of creator */ gid_t cgid; /* Effective GID of creator */ unsigned short mode; /* Permissions + SHM_DEST and SHM_LOCKED flags */ unsigned short __seq; /* Sequence number */ };
返回值:成功的IPC_INFO或SHM_INFO操作將返回內(nèi)核內(nèi)部數(shù)組中記錄所有共享內(nèi)存段信息的最高使用項(xiàng)的索引。(此信息可與重復(fù)的SHM_STAT操作一起使用,以獲得有關(guān)系統(tǒng)上所有共享內(nèi)存段的信息。)成功的SHM_STAT操作返回其索引在shmid中給出的共享內(nèi)存段標(biāo)識(shí)符。其他操作成功時(shí)返回0。
出現(xiàn)錯(cuò)誤時(shí),返回-1,并適當(dāng)設(shè)置errno。
3.5、流程
總結(jié)
共享內(nèi)存,可以大大加快對(duì)文件或設(shè)備的讀寫操作。共享內(nèi)存的方式有mmap和shmget 、 shmat。
所謂的零拷貝,就是不需要CPU的參與,而不是其他的意思。
mmap內(nèi)部其實(shí)是一個(gè)DMA技術(shù)。
以上就是深入學(xué)習(xí)C語(yǔ)言mmap和shm*的使用方法技巧的詳細(xì)內(nèi)容,更多關(guān)于C語(yǔ)言mmap shm*方法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
掌握C++:揭秘寫時(shí)拷貝與淺深拷貝之間的關(guān)系
探索C++的奧秘,本指南將揭秘寫時(shí)拷貝與淺深拷貝之間的微妙關(guān)系,摸索這些復(fù)雜概念背后的邏輯,讓你的編程技能瞬間提升,來(lái)吧,讓我們一起進(jìn)入這個(gè)引人入勝的C++世界!2024-01-01Vscode搭建遠(yuǎn)程c開發(fā)環(huán)境的圖文教程
很久沒(méi)有寫C語(yǔ)言了,今天抽空學(xué)習(xí)下C語(yǔ)言知識(shí),接下來(lái)通過(guò)本文給大家介紹Vscode搭建遠(yuǎn)程c開發(fā)環(huán)境的詳細(xì)步驟,本文通過(guò)圖文實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),需要的朋友參考下吧2021-11-11C++各種數(shù)據(jù)類型所占內(nèi)存大小詳解
這篇文章主要介紹了C++各種數(shù)據(jù)類型所占內(nèi)存大小,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08用c語(yǔ)言實(shí)現(xiàn)2000內(nèi)既能被3整除又能被7整除的個(gè)數(shù)
本篇文章是對(duì)使用c語(yǔ)言實(shí)現(xiàn)2000內(nèi)既能被3整除又能被7整除的個(gè)數(shù),用實(shí)例進(jìn)行了分析說(shuō)明,需要的朋友參考下2013-05-05C++中std::thread{}和std::thread()用法
std::thread{}和std::thread()在C++中都可以用于創(chuàng)建線程對(duì)象,但std::thread{}作為C++11引入的統(tǒng)一初始化,更推薦使用,因?yàn)樗踩⒏鬃x,且避免了隱式類型轉(zhuǎn)換2024-11-11C語(yǔ)言遞歸之漢諾塔和青蛙跳臺(tái)階問(wèn)題
這篇文章主要介紹了C語(yǔ)言遞歸之漢諾塔問(wèn)題和青蛙跳臺(tái)階問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04