linux進程共享內存
① 架構師進階: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兩個進程間共享內存通信都需要調用shmget函數么
兩個進程都需要調用shmget函數,是根據key值來實現訪問同一個共享內存的。
函數原型:int shmget(key_t key, size_t size, int shmflg)
由於是兩個進程訪問,最好是做兩手准備:
1,先創建,若創建成功,可以直接使用。
2,若創建失敗--此時,很可能另一個進程已經創建成功了,就不能再創建了。此時,就改為只是獲取。
示例代碼如下:
int mid = shmget(key, size, IPC_CREAT | 0660);
if(mid < 0){
mid = shmget(key, 0, 0);
}
③ linux多個子進程共享內存通信 c語言 用shmget或mmap
借個取決於那個進程先運行,結果是不確定的
或許需要用semget獲取信號燈來同步,來保證執行的順序
④ Linux進程間如何共享內存
創建共享內存 shmget()
映射共享內存 shmat()
(使用映射的內存)
解除映射. shmdt()
刪除共享內存 shmctl()
⑤ linux共享內存存在於進程空間的什麼位置
共享內存方式:從物理內存裡面拿出來一部分作為多個進程共享。 共享內存是進程間共享數據的一種最快的方法,一個進程向共享內存區域寫入數據,共享這個內存的所有進程都可以立即看到其中內容。 共享內存實現步驟: 一、創建共享內存,使用shmget函數。 二、映射共享內存,將這段創建的共享內存映射到具體的進程空間去,使用shmat函數。 創建共享內存shmget: intshmget(key_t key, size_t size, int shmflg) 功能:得到一個共享內存標識符或創建一個共享內存對象並返回共享內存標識符。 key: 0(IPC_PRIVATE)會建立共享內存對象 size:大於0的整數,新建共享內存的大小,以位元組為單位。只獲取共享內存時,指定為0. shmflg: 0表示取共享內存標識符,如不存在則函數會報錯; IPC_CREAT,如果內核中不存在鍵值與key相等的共享內存時,則創建一個共享內存;如果存在這樣的共享內存則返回共享內存的標識符; IPC_CREATIPC_EXCL: 如果內核中不存在鍵值與key相等的共享內存,則新建一個消息隊列;如果存在這樣的共享內存則報錯; 函數返回值:成功則返回內存的標識符;出錯則返回-1,錯誤原因存在於error中 映射共享內存到調用進程的地址空間shmat: void*shmat(int shmid, const void *shmaddr, int shmflg) msqid:共享內存標識符 shmaddr:指定共享內存出現在進程內存地址的什麼位置,直接指定為NULL讓內核自己決定一個合適的地址位置。 shmflg: SHM_RDONLY 只讀模式,其他為讀寫模式 函數返回值:成功則返回附加好的共享內存地址;出錯返回-1,錯誤原因存在於error中 斷開共享內存連接shmdt: intshmdt(const void *shmaddr) 功能:傳入shmaddr,連接共享的內存起始地址;斷開成功則返回0,出錯則返回-1,錯誤原因存在於error中。 父子進程間通訊實例: #include #include #include #include #include #include int main(int argc, char **argv){ if(argc< 2){ //需要輸入共享的數據 printf("pleaseinput the shared data.n"); exit(-1); } intshmid; shmid= shmget(0,1024,IPC_CREAT); if(shmid== -1){ // 申請共享內存失敗 printf("createshare memory failed.n"); exit(-1); } if(fork()){ // 父進程之中 char*p_shmaddr; p_shmaddr= shmat(shmid, NULL, 0); // 映射到父進程之中的一個地址 memset(p_shmaddr,0, 1024); // 初始化共享內存 strcpy(p_shmaddr,argv[1]); // 拷貝共享數據到共享內存 wait(NULL); //等待子進程結束 exit(0); } else{ sleep(2); //等待父進程寫入數據 char*c_shmaddr; c_shmaddr= shmat(shmid,NULL,0); // 映射到子進程之中一個地址,具體由kernel 指配 printf("theshare data is: %sn", c_shmaddr); //子進程輸出共享的數據 exit(0); } }
⑥ 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查看共享內存命令
共享內存查看
使用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 共享內存 可不可以不加鎖呢 系統有兩個進程,一個負責寫入,一個負責讀取
能.並且是"要"加鎖.可以使用信號量加鎖.
⑨ Linux下共享內存在進程空間的什麼位置
共享內存的創建 根據理論: 1. 共享內存允許兩個或多個進程共享一給定的存儲區,因為數據不需要來回復制,所以是最快的一種進程間通信機制。共享內存可以通過mmap()映射普通文件(特殊情況下還可以採用匿名映射)機制實現,也可以通過系統V共享
⑩ 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,它表示允許一個進程創建的共享內存被內存創建者所擁有的進程向共享內存讀取和寫入數據,同時其他用戶創建的進程只能讀取共享內存。