這次我們來講一下Linux進程通信中重要的通信方式:共享內存作為Linux軟件開發攻城獅,進程間通信是必須熟練掌握的重要技能,而共享內存是在程序開發中常用的也是重要的一種進程間通信方式。
下面我們就來聊一聊Linux下進程間如何實現共享內存通信,有哪些方式?
1、基本概念
UNIX 和 Linux
UNIX和Linux是兩種不同的操作系統,它們的主要區別在以下幾個方面:
歷史:UNIX是最早的商業化操作系統之一,最初由貝爾實驗室開發,而Linux則是由Linus Torvalds于1991年開發的開源操作系統。
源代碼:UNIX的源代碼是私有的,需要購買授權才能使用和修改,而Linux是開源的,任何人都可以自由地訪問、使用和修改其源代碼。
可移植性:由于UNIX的代碼是私有的,因此它們在不同的硬件平臺之間的可移植性較差。而Linux的源代碼是開放的,因此它可以在多種硬件平臺上運行。
發行版:UNIX有多個商業和非商業版本,如Solaris、AIX、HP-UX等,每個版本都有自己的特點和功能。而Linux則有許多不同的發行版,如Ubuntu、Debian、Red Hat、Fedora等。
命令行工具:UNIX和Linux有許多相同的命令行工具和命令,如ls、grep、awk等,但也有一些不同之處。
總的來說,UNIX和Linux都是基于UNIX哲學的操作系統,但它們在源代碼、可移植性、發行版和命令行工具等方面有所不同。
System V 和 POSIX
System V和POSIX是兩種不同的操作系統標準,它們的區別在以下幾個方面:
歷史背景:System V最初是由AT&T開發的UNIX版本,而POSIX是IEEE為了保證不同UNIX系統的兼容性而開發的標準。
體系結構:System V是一種具體的操作系統,而POSIX則是一種操作系統接口標準。因此,System V具有更多的操作系統特定功能,而POSIX的接口更為通用,適用于多種不同類型的UNIX系統。
文件系統:System V和POSIX的文件系統不同。System V使用名為“inode”的數據結構來描述文件和目錄,而POSIX則使用名為“文件描述符”的整數來表示打開的文件。
Shell:System V和POSIX的Shell也不同。System V的Shell是Bourne Shell,而POSIX的Shell是Bourne-Again Shell(bash)。
網絡支持:System V和POSIX的網絡支持也不同。System V使用TCP/IP協議棧,而POSIX使用套接字(socket)接口。
2、System V IPC 和 POSIX IPC
System V IPC(Interprocess Communication)和POSIX IPC都是用于在不同進程間進行通信的機制,但它們之間有幾個區別:
編程接口:System V IPC和POSIX IPC的編程接口不同。System V IPC使用IPC對象(如信號量、共享內存和消息隊列)來實現進程間通信,而POSIX IPC使用命名對象(如命名信號量、命名共享內存和命名管道)。
可移植性:POSIX IPC是由IEEE POSIX標準定義的,因此POSIX IPC是可移植的,可在不同的操作系統上使用。而System V IPC是由System V操作系統提供的,因此不同的操作系統可能實現不同,因此在跨平臺時可能會有問題。
接口和實現:System V IPC的接口和實現是緊密耦合的,而POSIX IPC的接口和實現是松散耦合的。這意味著在POSIX IPC中,接口和實現是獨立的,因此可以在實現中進行更改,而不影響接口,這使得在不同的系統上實現相同的接口變得更容易。
特性:System V IPC提供的特性比POSIX IPC多,例如,System V IPC提供了消息隊列,而POSIX IPC則沒有。另一方面,POSIX IPC提供了諸如命名管道之類的特性,而System V IPC則沒有。
綜上所述,System V IPC和POSIX IPC都有其優點和缺點。在選擇使用哪種IPC機制時,需要根據具體應用場景和需求進行權衡。
3、共享內存實現方式
在Linux下,共享內存可以使用System V IPC機制或POSIX IPC機制實現。
使用System V IPC機制:
使用shmget()函數創建共享內存區域并獲取其標識符。使用shmat()函數將共享內存區域附加到進程地址空間中。使用shmdt()函數將共享內存區域從進程地址空間中分離。使用shmctl()函數控制共享內存區域的屬性和狀態。
使用POSIX IPC機制:
使用shm_open()函數創建共享內存區域并獲取其文件描述符。使用ftruncate()函數調整共享內存區域的大小。使用mmap()函數將共享內存區域映射到進程地址空間中。使用munmap()函數解除共享內存區域與進程地址空間的映射關系。使用shm_unlink()函數刪除共享內存區域的文件名并釋放資源。
System V IPC機制實現共享內存
以下是一個使用System V IPC機制實現共享內存的簡單例程,它展示了如何創建、附加和分離共享內存區域。
#include?#include? #include? #include? #include? #define?SHM_SIZE?1024?//?共享內存大小 int?main()?{ ????int?shmid; ????char?*shmaddr; ????char?s8ReadBuf[1024]?=?{0}; ????key_t?key?=?ftok(".",?'s');?//?獲取共享內存標識符 ????if?(key?==?-1)?{ ????????perror("ftok"); ????????exit(1); ????} ????//?創建共享內存區域 ????shmid?=?shmget(key,?SHM_SIZE,?IPC_CREAT?|?0666); ????if?(shmid?==?-1)?{ ????????perror("shmget"); ????????exit(1); ????} ????//?將共享內存區域附加到進程地址空間中 ????shmaddr?=?shmat(shmid,?NULL,?0); ????if?(shmaddr?==?(char?*)?-1)?{ ????????perror("shmat"); ????????exit(1); ????} #if?1 ????//?在共享內存中寫入數據 ????strncpy(shmaddr,?"Hello,?world!",?SHM_SIZE); #else ????//?讀數據 ????//?memcpy(s8ReadBuf,?shmaddr,?1024); ????//?printf("s8ReadBuf:%s ",?s8ReadBuf); #endif ????//?分離共享內存區域 ????if?(shmdt(shmaddr)?==?-1)?{ ????????perror("shmdt"); ????????exit(1); ????} ????return?0; }
在上面的例程中,我們首先使用ftok()函數生成一個key值作為共享內存的標識符。然后使用shmget()函數創建共享內存區域,shmaddr指向共享內存區域的起始地址。最后使用shmdt()函數分離共享內存區域。
POSIX IPC機制實現共享內存
以下是一個使用POSIX IPC機制實現共享內存的簡單例程,它展示了如何創建、映射和解除映射共享內存區域。
#include?#include? #include? #include? #include? #include? #define?SHM_SIZE?1024?//?共享內存大小 #define?SHM_NAME?"/myshm"?//?共享內存名稱 int?main()?{ ????int?fd; ????char?*shmaddr; ????char?s8ReadBuf[1024]?=?{0}; ????const?char?*msg?=?"Hello,?world!"; ????//?創建共享內存區域 ????fd?=?shm_open(SHM_NAME,?O_CREAT?|?O_RDWR,?0666); ????if?(fd?==?-1)?{ ????????perror("shm_open"); ????????exit(1); ????} ????//?調整共享內存區域的大小 ????if?(ftruncate(fd,?SHM_SIZE)?==?-1)?{ ????????perror("ftruncate"); ????????exit(1); ????} ????//?映射共享內存區域到進程地址空間中 ????shmaddr?=?mmap(NULL,?SHM_SIZE,?PROT_READ?|?PROT_WRITE,?MAP_SHARED,?fd,?0); ????if?(shmaddr?==?MAP_FAILED)?{ ????????perror("mmap"); ????????exit(1); ????} #if?1 ????//?在共享內存中寫入數據 ????strncpy(shmaddr,?msg,?SHM_SIZE); #else ????//?讀數據 ????//?memcpy(s8ReadBuf,?shmaddr,?1024); ????//?printf("s8ReadBuf:%s ",?s8ReadBuf); #endif ????//?解除共享內存區域與進程地址空間的映射關系 ????if?(munmap(shmaddr,?SHM_SIZE)?==?-1)?{ ????????perror("munmap"); ????????exit(1); ????} ????//?刪除共享內存區域的文件名并釋放資源 ????if?(shm_unlink(SHM_NAME)?==?-1)?{ ????????perror("shm_unlink"); ????????exit(1); ????} ????return?0; }
在上面的例程中,我們使用shm_open()函數創建一個共享內存區域,然后使用ftruncate()函數調整共享內存區域的大小。接著,我們使用mmap()函數將共享內存區域映射到進程地址空間中,并使用strncpy()函數在共享內存中寫入數據。最后,我們使用munmap()函數解除共享內存區域與進程地址空間的映射關系,并使用shm_unlink()函數刪除共享內存區域的文件名并釋放資源。
小結
通過上面的示例希望對小伙伴們在共享內存通信編程中有所幫助,學會如何使用共享內存通信,并靈活運用于日常的編程中。共享內存方式的通信必須熟練掌握與應用。
編輯:黃飛
?
評論
查看更多