[英]Good alternative to shared memory IPC for Java/C++ apps on Linux
[英]Shared Memory or mmap - Linux C/C++ IPC
上下文是進程間通信,其中一個進程(“服務器”)必須將固定大小的結構發送到在同一台機器上運行的許多偵聽進程(“客戶端”)。
在Socket Programming中我很自在。 為了使服務器和客戶端之間的通信更快並減少副本數量,我想嘗試使用共享內存(shm)或mmaps。
操作系統是RHEL 64位。
由於我是新手,請建議我應該使用哪個。 如果有人能指點我一本書或在線資源來學習同樣的東西,我會很感激。
謝謝你的回答。 我想補充一點,服務器(市場數據服務器)通常會接收多播數據,這將導致它每秒向“客戶端”“發送”大約200,000個結構,其中每個結構大約為100字節。 shm_open / mmap實現是否僅對大型數據塊或大量小型結構的性能優於套接字?
我將mmap
與shm_open
一起用於將共享內存映射到進程的虛擬地址空間。 這是相對直接和干凈的:
"/myRegion"
shm_open
您可以在該區域上打開文件描述符 ftruncate
可以將段擴大到所需的大小 mmap
將其映射到您的地址空間 shmat
和Co接口(至少在歷史上)具有以下缺點:它們可能對您可以映射的最大內存量有限制。
然后,所有POSIX線程同步工具( pthread_mutex_t
, pthread_cond_t
, sem_t
, pthread_rwlock_t
,...)都具有初始化接口,允許您在進程共享上下文中使用它們。 所有現代Linux發行版都支持這一點。
這是否比套接字更可取? 性能方面它可能會有所不同,因為你不必復制東西。 但我想的主要觀點是,一旦你初始化了你的片段,這在概念上就更簡單了。 要訪問項目,您只需要鎖定共享鎖,讀取數據然后再次解鎖。
正如@R建議的那樣,如果你有多個讀者, pthread_rwlock_t
可能是最好的鎖結構。
我曾經使用共享內存段實現了IPC庫; 這讓我可以避免復制(而不是將數據從發送方內存復制到內核空間,然后從內核空間復制到接收方內存,我可以直接從發送方復制到接收方內存)。
無論如何,結果並不像我預期的那樣好:實際上共享一個內存段是一個非常昂貴的過程,因為重新映射TLB條目和所有其余的都非常昂貴。 有關詳細信息,請參閱此郵件 (我不是那些人之一,但在開發我的庫時會收到這樣的郵件)。
結果僅適用於非常大的消息(例如超過幾兆字節),如果您使用的是小緩沖區,除非您願意編寫內核模塊,否則unix套接字是您可以找到的最優化的東西。
除了已經提出的建議之外,我還想提供另一種方法:IPv6節點/接口本地多播,即受限於環回接口的多播。 http://www.iana.org/assignments/ipv6-multicast-addresses/ipv6-multicast-addresses.xml#ipv6-multicast-addresses-1
起初這可能看起來很重,但大多數操作系統在零拷貝架構中實現環回套接字。 映射到傳遞給send
的buf
參數的頁面將被分配一個額外的映射並在寫入時標記為copy,這樣如果發送程序覆蓋其中的數據,或者取消分配內容將被保留。
您應該使用強大的數據結構,而不是傳遞原始結構。 Netstrings http://cr.yp.to/proto/netstrings.txt和BSON http://bsonspec.org/浮現在腦海中。
在POSIX shm_open/mmap
接口和舊的System V shmop
之間進行選擇不會產生很大的不同,因為在初始化系統調用之后,您最終會遇到相同的情況:在各個進程之間共享的內存區域。 如果您的系統支持它,我建議使用shm_open/mmap
,因為這是一個設計更好的界面。
然后,您可以將共享內存區域用作通用黑板,其中所有進程都可以對其數據進行分頁。 困難的部分是同步訪問該區域的進程。 在這里,我建議避免編寫自己的同步方案,這可能非常困難且容易出錯。 相反,使用現有的基於工作套接字的實現來同步進程之間的訪問,並僅使用共享內存在進程之間傳輸大量數據。 即使使用這種方案,您也需要一個中央流程來協調緩沖區的分配,因此只有在您需要傳輸大量數據時,此方案才有價值。 或者,使用同步庫,如Boost.Interprocess 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.