共享內存linux
Ⅰ linux進程通信實驗(共享內存通信,接上篇)
這一篇記錄一下共享內存實驗,需要linux的共享內存機制有一定的了解,同時也需要了解POSIX信號量來實現進程間的同步。可以參考以下兩篇博客: https://blog.csdn.net/sicofield/article/details/10897091
https://blog.csdn.net/ljianhui/article/details/10253345
實驗要求:編寫sender和receiver程序,sender創建一個共享內存並等待用戶輸入,然後把輸入通過共享內存發送給receiver並等待,receiver收到後把消息顯示在屏幕上並用同樣方式向sender發送一個over,然後兩個程序結束運行。
這個實驗的難點主要在於共享內存的創建和撤銷(涉及到的步驟比較多,需要理解各步驟的功能),以及實現兩個進程間的相互等待(使用信號量來實現,這里使用了有名信號量)
實驗心得:學習理解了linux的共享內存機制以及POSIX信號量機制。
兩個實驗雖然加強了對linux一些機制的理解,但是感覺對linux的學習還不夠,需要繼續學習。
Ⅱ linux 共享內存 可不可以不加鎖呢 系統有兩個進程,一個負責寫入,一個負責讀取
能.並且是"要"加鎖.可以使用信號量加鎖.
Ⅲ 如何設置linux的共享內存
在 Linux 中設置共享內存的方法有很多種,下面是一種常用的方法:
使用shmget()函數創建一塊共享內存,可以指定共享內存的大小和標識符。
使用shmat()函數將共享內存連接到進程的地址空間,返回指向共享內存的指針。
使用shmdt()函數斷開與共享內存的連接。
使用shmctl()函數刪除共享內存。
具體實現可以參考以下代碼示例:
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
int main() {
// 1. 創建共享內存
int shmid = shmget(IPC_PRIVATE, 100, 0666 | IPC_CREAT);
if (shmid < 0) {
perror("shmget error");
return 1;
}
// 2. 連接共享內沒瞎存
void *shm = shmat(shmid, NULL, 0);
if (shm == (void *)-1) {
perror("shmat error");
return 1;
}
// 使用共享內存
// ...
// 3. 斷開連接
if (shmdt(shm) < 0) {
perror("shmdt error");
return 1;
}
// 4. 刪除共享內存
if (shmctl(shmid, IPC_RMID, 0) < 0) {
perror("shmctl error");
return 1;
}
return 0;
}
這是一個簡單的示枯雹空例,在這里我們創建了一個大小為100位元組的共享內肆備存,並使用shmget()、shmat()、shmdt()、shmctl()四個函數來創建、連接、斷開連接、刪除共享內存。
在實際應用中,我們需要根據需要來調整共享內存的大小,並在使用共享內存時進行相應的同步和互斥操作來保證數據的安全性。
需要注意的是,在使用共享內存時,我們需要確保共享內存在進程全部退出後能夠被釋放,這可以通過在父進
程中刪除共享內存來實現。另外在程序中也要考慮到異常處理,如果在程序運行過程中發生了異常,應該及時釋放所佔用的共享內存,以免造成資源浪費。
另外需要提醒的是,共享內存是一種高級的IPC(Inter-Process Communication)機制,使用時需要謹慎,避免出現數據競爭和死鎖等問題。
Ⅳ linux兩種共享內存的區別
持久性不同、文件反射方式不同。
1、持久性不同。sysvshm是持久化的,除非被一個進程明確的刪除,否則它始終存在於內存里,直到系統關機。mmap映射的內存在不是持久化的,假如進程關閉,映射隨即失效,除非事前已經映射到了一個文件上。
2、文件反射方式不同。前者用COW的方式,把文件映射到當前的進程空間,修改操作不會改動源文件。後者直接把文件映射到當前的進程空間,所有的修改會直接反應到文件的page cache,而後由內核自動同步到映射文件上。
Ⅳ linux共享內存的控制釋放
調用 shmctl(Shared Memory Control,控制共享內渣賀存)函數會返回一個共享內存塊孫棗的相關信息。同時 shmctl 允許程序修改這些信息。該函數的第一個參數是一個共享內存塊標識。
要獲取一個共享內存塊的相關信息,則為該函數傳遞 IPC_STAT 作為第二個參數,同時傳遞一個指向一個 struct shmid_ds 對象的指針作為第三個參數。
要刪除一個共享內存塊,則應將 IPC_RMID 作為第二個參數,而將 NULL 作為第三個參數。當最後一個綁定該共享內存塊的進程與其脫離時,該共享內存塊將被刪除。
您應當在結束使用每個共享內存塊的時候都使用 shmctl 進行釋放,以防止超過系統所允許的共享內存塊的總數限制。調用 exit 和 exec 會使進程脫離共享內存塊,但不會刪除這個內存塊。 要查看其它有關共享內存塊的操作的描述如凱派,請參考shmctl函數的手冊頁。
Ⅵ linux系統的進程間通信有哪幾種方式
一、方式
1、管道(Pipe)及有名管道( mkpipe):
管道可用於具有親緣關系進程間的通信,有名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關系進程間的通信;
2、信號(Signal):
信號是比較復雜的通信方式,用於通知接受進程有某種事件發生,除了用於進程間通信外,進程還可以發送信號給進程本身。
linux除了支持Unix早期信號語義函數sigal外,還支持語義符合Posix.1標準的信號函數sigaction。
實際上,該函數是基於BSD的,BSD為了實現可靠信號機制,又能夠統一對外介面,用sigaction函數重新實現了signal函數。
3、消息隊列(Message):
消息隊列是消息的鏈接表,包括Posix消息隊列system V消息隊列。有足夠許可權的進程可以向隊列中添加消息,被賦予讀許可權的進程則可以讀走隊列中的消息。消息隊列克服了信號承載信息量少,管道只能承載無格式位元組流以及緩沖區大小受限等缺點。
4、共享內存:
使得多個進程可以訪問同一塊內存空間,是最快的可用IPC形式。是針對其他通信機制運行效率較低而設計的。往往與其它通信機制,如信號量結合使用,來達到進程間的同步及互斥。
5、信號量(semaphore):
主要作為進程間以及同一進程不同線程之間的同步手段。
6、套介面(Socket):
更為一般的進程間通信機制,可用於不同機器之間的進程間通信。起初是由Unix系統的BSD分支開發出來的,但現在一般可以移植到其它類Unix系統上:Linux和System V的變種都支持套接字。
二、概念
進程間通信概念:
IPC—-InterProcess Communication
每個進程各自有不同的用戶地址空間,任何一個進程的全局變數在另一個進程中都看不到所以進程之間要交換數據必須通過內核。
在內核中開辟一塊緩沖區,進程1把數據從用戶空間拷到內核緩沖區,進程2再從內核緩沖區把數據讀走,內核提供的這種機制稱為進程間通信。
(6)共享內存linux擴展閱讀
1)無名管道:
管道是半雙工的,數據只能向一個方向流動;需要雙方通信時,需要建立起兩個管道;只能用於父子進程或者兄弟進程之間(具有親緣關系的進程)。
管道對於管道兩端的進程而言,就是一個文件,但它不是普通的文件,它不屬於某種文件系統,構成兩進程間通信的一個媒介。
數據的讀出和寫入:一個進程向管道中寫的內容被管道另一端的進程讀出。寫入的內容每次都添加在管道緩沖區的末尾,並且每次都是從緩沖區的頭部讀出數據。
2)有名管道:
不同於管道之處在於它提供一個路徑名與之關聯,以FIFO的文件形式存在於文件系統中。這樣,即使與FIFO的創建進程不存在親緣關系的進程,只要可以訪問該路徑,就能夠彼此通過FIFO相互通信(能夠訪問該路徑的進程以及FIFO的創建進程之間)。
因此,通過FIFO不相關的進程也能交換數據。值得注意的是,FIFO嚴格遵循先進先出(first in first out),對管道及FIFO的讀總是從開始處返回數據,對它們的寫則把數據添加到末尾。它們不支持諸如lseek()等文件定位操作。
Ⅶ 如何設置LINUX的共享內存
我們可以修改shmmax內核參數,使SGA存在於一個共享內存段中。
通過修改/proc/sys/kernel/shmmax參數可以達到此目的。
[root@neirong root]# echo 1073741824 > /proc/sys/kernel/shmmax
[root@neirong root]# more /proc/sys/kernel/shmmax
1073741824這里設為1G。
對於shmmax文件的修改,系統重新啟動後會復位。可以通過修改 /etc/sysctl.conf 使更改永久化。
在該文件內添加以下一行 kernel.shmmax = 1073741824 這個更改在系統重新啟動後生效.
1、設置 SHMMAX
SHMMAX
參數定義共享內存段的最大尺寸(以位元組為單位)。在設置 SHMMAX 時,切記 SGA 的大小應該適合於一個共享內存段。 SHMMAX 設置不足可能會導致以下問題:
ORA-27123:unable to attach to shared memory segment
您可以通過執行以下命令來確定 SHMMAX 的值枝毀:
# cat /proc/sys/kernel/shmmax
33554432
SHMMAX 的默認值是 32MB 。我一般使用下列方法之一種將 SHMMAX 參數設為 2GB :
通過直接更改 /proc 文件系統,你不需重新啟動機器就可以改變 SHMMAX 的默認設置。我使用的方法是將手裂以下命令放入 /etc/rc.local 啟動文件中:
# >echo "2147483648" > /proc/sys/kernel/shmmax
您還可以使用 sysctl 命令來更改 SHMMAX 的值:
# sysctl -w kernel.shmmax=2147483648
最後,通過將該內核參數插入到 /etc/sysctl.conf 啟動文件中,您可以使這種更改永久有效:
# echo "kernel.shmmax=2147483648" >> /etc/sysctl.conf
2、設置 SHMMNI
我們現在來看 SHMMNI 參數。這個內核參數用於設置系統范圍內共享內存段的最大數量。該參數的默認值是 4096 。這一數值已經足夠,通常不需要更改。
您可以通過執行以下命令來確定 SHMMNI 的值:
猛薯備# cat /proc/sys/kernel/shmmni
4096
3、設置 SHMALL
最後,我們來看 SHMALL 共享內存內核參數。該參數控制著系統一次可以使用的共享內存總量(以頁為單位)。簡言之,該參數的值始終應該至少為:
ceil(SHMMAX/PAGE_SIZE)
SHMALL 的默認大小為 2097152 ,可以使用以下命令進行查詢:
# cat /proc/sys/kernel/shmall
2097152
SHMALL 的默認設置對於我們的 Oracle9 i RAC 安裝來說應該足夠使用。
注意: 在 i386 平台上 Red Hat Linux 的 頁面大小 為 4096 位元組。但是,您可以使用 bigpages ,它支持配置更大的內存頁面尺寸。
Ⅷ linux查看共享內存命令
共享內存查看
使用ipcs命令,不加如何參數時,會把共享內存、信號量、消息隊列的信息都列印出來,如果只想顯示共享內存信息,使用如下命令:
[root@localhost ~]# ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 1867776 root 600 393216 2 dest
0x00000000 1900545 root 600 393216 2 dest
0x00030021 1703938 zc 666 131104 1
0x0003802e 1736707 zc 666 131104 1
0x00030004 1769476 zc 666 131104 1
0x00038002 1802245 zc 666 131104 1
0x00000000 1933318 root 600 393216 2 dest
0x00000000 1966087 root 600 393216 2 dest
0x00000000 1998856 root 600 393216 2 dest
0x00000000 2031625 root 600 393216 2 dest
0x00000000 2064394 root 600 393216 2 dest
0x0014350c 2261003 cs 666 33554432 2
0x00000000 2129932 root 600 393216 2 dest
0x00000000 2162701 root 600 393216 2 dest
0x00143511 395837454 root 666 1048576 1
其中:
第一列就是共享內存的key;
第二列是共享內存的編號shmid;
第三列就是創建的用戶owner;
第四列就是許可權perms;
第五列為創建的大小bytes;
第六列為連接到共享內存的進程數nattach;
第七列是共享內存的狀態status。其中顯示「dest」表示共享內存段已經被刪除,但是還有用戶在使用它,當該段內存的mode欄位設置為SHM_DEST時就會顯示「dest」。當用戶調用shmctl的IPC_RMID時,內存先查看多少個進程與這個內存關聯著,如果關聯數為0,就會銷毀這段共享內存,否者設置這段內存的mod的mode位為SHM_DEST,如果所有進程都不用則刪除這段共享內存。
Ⅸ linux共享內存的示常式序
代碼 5.1 中的程序展示了共享內存塊的使用。
代碼 5.1 (shm.c) 嘗試共享內存
#include <stdio.h>
#include <sys/shm.h>
#include <sys/stat.h>
int main()
{
int segment_id;
char* shared_memory;
struct shmid_ds shmbuffer;
int segment_size;
const int shared_segment_size = 0x6400; /* 分配一個共享內存塊 */
segment_id = shmget(IPC_PRIVATE, shared_segment_size, IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR ); /* 綁定到共享內存塊 */
shared_memory = (char*)shmat(segment_id, 0, 0);
printf(shared memory attached at address %p
, shared_memory); /* 確定共享內存的大小 */
shmctl(segment_id, IPC_STAT, &shmbuffer);
segment_size = shmbuffer.shm_segsz;
printf(segment size: %d
, segment_size);
sprintf(shared_memory, Hello, world.); /* 在共享內存中寫入一個字元串 */
shmdt(shared_memory); /* 脫離該共享內存塊 */
shared_memory = (char*)shmat(segment_id, (void*) 0x500000, 0);/* 重新綁定該內存塊 */
printf(shared memory reattached at address %p
, shared_memory);
printf(%s
, shared_memory); /* 輸出共享內存中的字元串 */
shmdt(shared_memory); /* 脫離該共享內存塊 */
shmctl(segment_id, IPC_RMID, 0);/* 釋放這個共享內存塊 */
return 0;
}
Ⅹ 探討一下 Linux 共享內存的 N 種方式
關於 Linux 共享內存,寫得最好的應該是宋寶華的 《世上最好的共享內存》 一文。
本文可以說是對這篇文章的學習筆記,順手練習了一下 rust libc —— shichaoyuan/learn_rust/linux-shmipc-demo
按照宋寶華的總結,當前有四種主流的共享內存方式:
前兩種方式比較符合傳統的用法,共享內存做為進程間通信的媒介。
第三種方式更像是通過傳遞內存「句柄」進行數據傳輸。
第四種方式是為設備間傳遞數據設計,避免內存拷貝,直接傳遞內存「句柄」。
這里嘗試了一下第二種和第三種方式。
這套 API 應該是最普遍的 —— shm_open + mmap,本質上來說 Aeron 也是用的這種方式(關於 Aeron 可以參考 我之前的文章 )。
看一下 glibc 中 shm_open 函數的實現就一清二楚了:
shm_open 函數就是在 /dev/shm 目錄下建文件,該目錄掛載為 tmpfs,至於 tmpfs 可以簡單理解為存儲介質是內存的一種文件系統,更准確的理解可以參考官方文檔 tmpfs.txt 。
然後通過 mmap 函數將 tmpfs 文件映射到用戶空間就可以隨意操作了。
優點:
這種方式最大的優勢在於共享的內存是有「實體」(也就是 tmpfs 中的文件)的,所以多個進程可以很容易通過文件名這個信息構建共享內存結構,特別適合把共享內存做為通信媒介的場景(例如 Aeron )。
缺點:
如果非要找一個缺點的話,可能是,文件本身獨立於進程的生命周期,在使用完畢後需要注意刪除文件(僅僅 close 是不行的),否則會一直佔用內存資源。
memfd_create 函數的作用是創建一個匿名的文件,返回對應的 fd,這個文件當然不普通,它存活在內存中。更准確的理解可以參考官方文檔 memfd_create(2) 。
直觀理解,memfd_create 與 shm_open 的作用是一樣的,都是創建共享內存實體,只是 memfd_create 創建的實體是匿名的,這就帶了一個問題:如何讓其它進程獲取到匿名的實體?shm_open 方式有具體的文件名,所以可以通過打開文件的方式獲取,那麼對於匿名的文件怎麼處理呢?
答案是:通過 Unix Domain Socket 傳遞 fd。
rust 的 UDS 實現:
rust 在 std 中已經提供了 UDS 的實現,但是關於傳遞 fd 的 send_vectored_with_ancillary 函數還屬於 nightly-only experimental API 階段。所以這里使用了一個三方 crate —— sendfd ,坦白說可以自己實現一下,使用 libc 構建好 SCM_RIGHTS 數據,sendmsg 出去即可,不過細節還是挺多,我這里就放棄了。
這套 API 設計更靈活,直接拓展了我的思路,本來還是受限於 Aeron 的用法,如果在這套 API 的加持下,是否可以通過傳遞數據包內存塊(fd)真正實現零拷貝呢?
優點:
靈活。
缺點:
無