導航:首頁 > 編程語言 > linux編程共享內存

linux編程共享內存

發布時間:2022-10-19 03:15:26

① 架構師進階:linux進程間如何共享內存

共享內存 IPC 原理
共享內存進程間通信機制主要用於實現進程間大量的數據傳輸,下圖所示為進程間使用共享內存實現大量數據傳輸的示意圖:

640

共享內存是在內存中單獨開辟的一段內存空間,這段內存空間有自己特有的數據結構,包括訪問許可權、大小和最近訪問的時間等。該數據結構定義如下:

from /usr/include/linux/shm.h
struct shmid_ds {
struct ipc_perm shm_perm; /* operation perms 操作許可權 */
int shm_segsz; /* size of segment (bytes) 段長度大小 */
__kernel_time_t shm_atime; /* last attach time 最近attach時間 */
__kernel_time_t shm_dtime; /* last detach time 最近detach時間 */
__kernel_time_t shm_ctime; /* last change time 最近change時間 */
__kernel_ipc_pid_t shm_cpid; /* pid of creator 創建者pid */
__kernel_ipc_pid_t shm_lpid; /* pid of last operator 最近操作pid */
unsigned short shm_nattch; /* no. of current attaches */
unsigned short shm_unused; /* compatibility */
void *shm_unused2; /* ditto - used by DIPC */
void *shm_unused3; /* unused */|
};
兩個進程在使用此共享內存空間之前,需要在進程地址空間與共享內存空間之間建立聯系,即將共享內存空間掛載到進程中。

系統對共享內存做了以下限制:

#define SHMMAX 0x2000000 /* max shared seg size (bytes) 最大共享段大小 */

#define SHMMIN 1 /* min shared seg size (bytes) 最小共享段大小 */

#define SHMMNI 4096 /* max num of segs system wide */

#define SHMALL (SHMMAX/getpagesize()*(SHMMNI/16))|

define SHMSEG SHMMNI /* max shared segs per process */

Linux 共享內存管理
1.創建共享內存

#include <sys/ipc.h> #include <sys/shm.h>
/*
* 第一個參數為 key 值,一般由 ftok() 函數產生
* 第二個參數為欲創建的共享內存段大小(單位為位元組)
* 第三個參數用來標識共享內存段的創建標識
*/

int shmget(key_t key, size_t size, int shmflg);
2.共享內存控制

#include <sys/ipc.h> #include <sys/shm.h>
/*
* 第一個參數為要操作的共享內存標識符
* 第二個參數為要執行的操作
* 第三個參數為 shmid_ds 結構的臨時共享內存變數信息
*/

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
3.映射共享內存對象

系統調用 shmat() 函數實現將一個共享內存段映射到調用進程的數據段中,並返回內存空間首地址,其函數聲明如下:

#include <sys/types.h>

#include <sys/shm.h>
/*
* 第一個參數為要操作的共享內存標識符
* 第二個參數用來指定共享內存的映射地址,非0則為此參數,為0的話由系統分配
* 第三個參數用來指定共享內存段的訪問許可權和映射條件
*/

void *shmat(int shmid, const void *shmaddr, int shmflg);
4.分離共享內存對象

在使用完畢共享內存空間後,需要使用 shmdt() 函數調用將其與當前進程分離。函數聲明如下:

#include <sys/types.h>

#include <sys/shm.h>
/*
* 參數為分配的共享內存首地址
*/

int shmdt(const void *shmaddr);

共享內存在父子進程間遵循的約定
1.使用 fork() 函數創建一個子進程後,該進程繼承父親進程掛載的共享內存。

2.如果調用 exec() 執行一個新的程序,則所有掛載的共享內存將被自動卸載。

3.如果在某個進程中調用了 exit() 函數,所有掛載的共享內存將與當前進程脫離關系。

程序實例
申請一段共享內存,父進程在首地址處存入一整數,子進程讀出。

#include

#include <sys/ipc.h>

#include <sys/shm.h>

#include <sys/types.h>

#include

#include

#define SHM_SIZE 1024

int main()

{

int shm_id, pid;

int *ptr = NULL;
/* 申請共享內存 */

shm_id = shmget((key_t)1004, SHM_SIZE, IPC_CREAT | 0600);
/* 映射共享內存到進程地址空間 */

ptr = (int*)shmat(shm_id, 0, 0);

printf("Attach addr is %p ", ptr);

*ptr = 1004;

printf("The Value of Parent is : %d ", *ptr);

if((pid=fork()) == -1){

perror("fork Err");

exit(0);

}

else if(!pid){
printf("The Value of Child is : %d ", *ptr);
exit(0);
}else{
sleep(1);
/* 解除映射 */

shmdt(ptr);
/* 刪除共享內存 */

shmctl(shm_id, IPC_RMID, 0);
}
return 0;
}
輸出結果:

640

② 探討一下 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)真正實現零拷貝呢?

優點:
靈活。

缺點:

③ 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的共享內存

我們可以修改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

⑤ 如何設置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的共享內存

我們可以修改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共享內存的分配

進程通過調用shmget(Shared Memory GET,獲取共享內存)來分配一個共享內存塊。
該函數的第一個參數是一個用來標識共享內存塊的鍵值。彼此無關的進程可以通過指定同一個鍵以獲取對同一個共享內存塊的訪問。不幸的是,其它程序也可能挑選了同樣的特定值作為自己分配共享內存的鍵值,從而產生沖突。用特殊常量IPC_PRIVATE作為鍵值可以保證系統建立一個全新的共享內存塊。
該函數的第二個參數指定了所申請的內存塊的大小。因為這些內存塊是以頁面為單位進行分配的,實際分配的內存塊大小將被擴大到頁面大小的整數倍。
第三個參數是一組標志,通過特定常量的按位或操作來shmget。這些特定常量包括:
IPC_CREAT:這個標志表示應創建一個新的共享內存塊。通過指定這個標志,我們可以創建一個具有指定鍵值的新共享內存塊。
IPC_EXCL:這個標志只能與 IPC_CREAT 同時使用。當指定這個標志的時候,如果已有一個具有這個鍵值的共享內存塊存在,則shmget會調用失敗。也就是說,這個標志將使線程獲得一個「獨有」的共享內存塊。如果沒有指定這個標志而系統中存在一個具有相同鍵值的共享內存塊,shmget會返回這個已經建立的共享內存塊,而不是重新創建一個。
模式標志:這個值由9個位組成,分別表示屬主、屬組和其它用戶對該內存塊的訪問許可權。其中表示執行許可權的位將被忽略。指明訪問許可權的一個簡單辦法是利用<sys/stat.h>中指定,並且在手冊頁第二節stat條目中說明了的常量指定。例如,S_IRUSR和S_IWUSR分別指定了該內存塊屬主的讀寫許可權,而 S_IROTH和S_IWOTH則指定了其它用戶的讀寫許可權。 下面例子中shmget函數創建了一個新的共享內存塊(當shm_key已被佔用時則獲取對一個已經存在共享內存塊的訪問),且只有屬主對該內存塊具有讀寫許可權,其它用戶不可讀寫。
int segment_id = shmget (shm_key, getpagesize (), IPC_CREAT | S_IRUSR| S_IWUSR ); 如果調用成功,shmget將返回一個共享內存標識符。如果該共享內存塊已經存在,系統會檢查訪問許可權,同時會檢查該內存塊是否被標記為等待摧毀狀態。

⑧ 如何設置linux的共享內存

首先先使用shmget建立一塊共享內存,然後向該內存中寫入數據並返回該共享內存shmid
使用另一個程序通過上一程序返回的shmid讀該共享內存內的數據
建立共享內存並寫入數據的程序

#include<stdio.h>
#include<string.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
#include<errno.h>
voidget_buf(char*buf)
{
inti=0;
while((buf[i]=getchar())!=' '&&i<1024)
i++;
}
intmain(void)
{
intshmid;
shmid=shmget(IPC_PRIVATE,sizeof(char)*1024,IPC_CREAT|0666);
if(shmid==-1)
{
perror("shmget");
}
char*buf;
if((int)(buf=shmat(shmid,NULL,0))==-1)
{
perror("shmat");
exit(1);
}
get_buf(buf);
printf("%d ",shmid);
return0;
}
讀取數據的程序
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
intmain(intargc,char**argv)
{
intshmid;
shmid=atoi(argv[1]);
char*buf;
if((int)(buf=shmat(shmid,NULL,0))==-1)
{
perror("shmat");
exit(1);
}
printf("%s ",buf);
shmdt(buf);
return0;
}

命令行的第一個參數設為第一個程序輸出的數字

使用完以後可以使用
ipcrm -m 19562507
來刪除該共享內存

⑨ linux共享內存使用的過程

Linux共享內存使用的過程?

一、什麼是共享內存
顧名思義,共享內存就是允許兩個不相關的進程訪問同一個邏輯內存。共享內存是在兩個正在運行的進程之間共享和傳遞數據的一種非常有效的方式。不同進程之間共享的內存通常安排為同一段物理內存。進程可以將同一段共享內存連接到它們自己的地址空間中,所有進程都可以訪問共享內存中的地址,就好像它們是由用C語言函數malloc分配的內存一樣。而如果某個進程向共享內存寫入數據,所做的改動將立即影響到可以訪問同一段共享內存的任何其他進程。

特別提醒:共享內存並未提供同步機制,也就是說,在第一個進程結束對共享內存的寫操作之前,並無自動機制可以阻止第二個進程開始對它進行讀取。所以我們通常需要用其他的機制來同步對共享內存的訪問,例如前面說到的信號量。

二、共享內存的使用
與信號量一樣,在Linux中也提供了一組函數介面用於使用共享內存,而且使用共享共存的介面還與信號量的非常相似,而且比使用信號量的介面來得簡單。它們聲明在頭文件 sys/shm.h中。
1、shmget函數
該函數用來創建共享內存,它的原型為:
int shmget(key_t key, size_t size, int shmflg);
第一個參數,與信號量的semget函數一樣,程序需要提供一個參數key(非0整數),它有效地為共享內存段命名,shmget函數成功時返回一個與key相關的共享內存標識符(非負整數),用於後續的共享內存函數。調用失敗返回-1.

不相關的進程可以通過該函數的返回值訪問同一共享內存,它代表程序可能要使用的某個資源,程序對所有共享內存的訪問都是間接的,程序先通過調用shmget函數並提供一個鍵,再由系統生成一個相應的共享內存標識符(shmget函數的返回值),只有shmget函數才直接使用信號量鍵,所有其他的信號量函數使用由semget函數返回的信號量標識符。

第二個參數,size以位元組為單位指定需要共享的內存容量

第三個參數,shmflg是許可權標志,它的作用與open函數的mode參數一樣,如果要想在key標識的共享內存不存在時,創建它的話,可以與IPC_CREAT做或操作。共享內存的許可權標志與文件的讀寫許可權一樣,舉例來說,0644,它表示允許一個進程創建的共享內存被內存創建者所擁有的進程向共享內存讀取和寫入數據,同時其他用戶創建的進程只能讀取共享內存。

閱讀全文

與linux編程共享內存相關的資料

熱點內容
如何保證伺服器優質 瀏覽:92
小微信aPP怎麼一下找不到了 瀏覽:299
演算法纂要學術價值 瀏覽:973
程序員你好是什麼意思 瀏覽:799
倩女幽魂老伺服器如何玩 瀏覽:559
電子鍾單片機課程設計實驗報告 瀏覽:997
看加密頻道 瀏覽:379
程序員算不算流水線工人 瀏覽:632
三星電視我的app怎麼卸載 瀏覽:44
簡述vi編譯器的基本操作 瀏覽:507
讓程序員選小號 瀏覽:91
加強數字貨幣國際信息編譯能力 瀏覽:584
購買的app會員怎麼退安卓手機 瀏覽:891
程序員的種類及名稱 瀏覽:293
美國程序員薪資 瀏覽:13
黑石通匯證券伺服器什麼時候到期 瀏覽:393
東方財富app里我的關注怎麼看 瀏覽:749
bm3d單反級降噪演算法 瀏覽:457
華為安卓機激活時間怎麼查詢 瀏覽:850
如何用優盤重裝伺服器系統 瀏覽:317