1. 程式人生 > >Linux下共享記憶體相關函式

Linux下共享記憶體相關函式

shmctl函式原型編輯
shmctl(共享記憶體管理)
所需標頭檔案
#include <sys/types.h>
#include <sys/shm.h>
函式說明
完成對共享記憶體的控制
函式原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
函式傳入值
shmid
共享記憶體識別符號
cmd
IPC_STAT:得到共享記憶體的狀態,把共享記憶體的shmid_ds結構複製到buf中
IPC_SET:改變共享記憶體的狀態,把buf所指的shmid_ds結構中的uid、gid、mode複製到共享記憶體的shmid_ds結構內
IPC_RMID:刪除這片共享記憶體
buf
共享記憶體管理結構體。具體說明參見共享記憶體核心結構定義部分
函式返回值
成功:0
出錯:-1,錯誤原因存於error中
錯誤程式碼
EACCESS:引數cmd為IPC_STAT,確無許可權讀取該共享記憶體
EFAULT:引數buf指向無效的記憶體地址
EIDRM:識別符號為shmid的共享記憶體已被刪除
EINVAL:無效的引數cmd或shmid
EPERM:引數cmd為IPC_SET或IPC_RMID,卻無足夠的許可權執行
其他共享記憶體函式編輯
shmat
shmat(把共享記憶體區物件對映到呼叫程序的地址空間)
所需標頭檔案
#include <sys/types.h>
#include <sys/shm.h>
函式說明
連線共享記憶體識別符號為shmid的共享記憶體,連線成功後把共享記憶體區物件對映到呼叫程序的地址空間,隨後可像本地空間一樣訪問
函式原型
void *shmat(int shmid, const void *shmaddr, int shmflg)
函式傳入值
msqid
共享記憶體識別符號
shmaddr
指定共享記憶體出現在程序記憶體地址的什麼位置,直接指定為NULL讓核心自己決定一個合適的地址位置
shmflg
SHM_RDONLY:為只讀模式,其他為讀寫模式
函式返回值
成功:附加好的共享記憶體地址
出錯:-1,錯誤原因存於error中
附加說明
fork後子程序繼承已連線的共享記憶體地址。exec後該子程序與已連線的共享記憶體地址自動脫離(detach)。程序結束後,已連線的共享記憶體地址會自動脫離(detach)
錯誤程式碼
EACCES:無許可權以指定方式連線共享記憶體
EINVAL:無效的引數shmid或shmaddr
ENOMEM:核心記憶體不足
shmget函式原型編輯
shmget(得到一個共享記憶體識別符號或建立一個共享記憶體物件)
所需標頭檔案
#include <sys/ipc.h>
#include <sys/shm.h>
函式說明
得到一個共享記憶體識別符號或建立一個共享記憶體物件並返回共享記憶體識別符號
函式原型
int shmget(key_t key, size_t size, int shmflg)
函式傳入值
key
0(IPC_PRIVATE):會建立新共享記憶體物件
大於0的32位整數:視引數shmflg來確定操作。通常要求此值來源於ftok返回的IPC鍵值
size
大於0的整數:新建的共享記憶體大小,以位元組為單位
0:只獲取共享記憶體時指定為0
shmflg
0:取共享記憶體識別符號,若不存在則函式會報錯
IPC_CREAT:當shmflg&IPC_CREAT為真時,如果核心中不存在鍵值與key相等的共享記憶體,則新建一個共享記憶體;如果存在這樣的共享記憶體,返回此共享記憶體的識別符號
IPC_CREAT|IPC_EXCL:如果核心中不存在鍵值與key相等的共享記憶體,則新建一個訊息佇列;如果存在這樣的共享記憶體則報錯
函式返回值
成功:返回共享記憶體的識別符號
出錯:-1,錯誤原因存於error中
附加說明
上述shmflg引數為模式標誌引數,使用時需要與IPC物件存取許可權(如0600)進行|運算來確定訊號量集的存取許可權
錯誤程式碼
EINVAL:引數size小於SHMMIN或大於SHMMAX
EEXIST:預建立key所指的共享記憶體,但已經存在
EIDRM:引數key所指的共享記憶體已經刪除
ENOSPC:超過了系統允許建立的共享記憶體的最大值(SHMALL)
ENOENT:引數key所指的共享記憶體不存在,而引數shmflg未設IPC_CREAT位
EACCES:沒有許可權
ENOMEM:核心記憶體不足
在Linux環境中,對開始申請的共享記憶體空間進行了初始化,初始值為0x00。
如果用shmget建立了一個新的訊息佇列物件時,則shmid_ds結構成員變數的值設定如下:
? shm_lpid、shm_nattach、shm_atime、shm_dtime設定為0。
? msg_ctime設定為當前時間。
? shm_segsz設成建立共享記憶體的大小。
? shmflg的讀寫許可權放在shm_perm.mode中。
? shm_perm結構的uid和cuid成員被設定成當前程序的有效使用者ID,gid和cuid成員被設定成當前程序的有效組ID。
shmdt函式原型編輯
shmdt(斷開共享記憶體連線)
所需標頭檔案
#include <sys/types.h>
#include <sys/shm.h>
函式說明
與shmat函式相反,是用來斷開與共享記憶體附加點的地址,禁止本程序訪問此片共享記憶體
函式原型
int shmdt(const void *shmaddr)
函式傳入值
shmaddr:連線的共享記憶體的起始地址
函式返回值
成功:0
出錯:-1,錯誤原因存於error中
附加說明
本函式呼叫並不刪除所指定的共享記憶體區,而只是將先前用shmat函式連線(attach)好的共享記憶體脫離(detach)目前的程序
錯誤程式碼
EINVAL:無效的引數shmaddr
共享記憶體應用範例編輯
1、父子程序通訊範例 父子程序通訊範例,shm.c原始碼如下:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <error.h>
#define SIZE 1024
int main()
{
int shmid ;
char *shmaddr ;
struct shmid_ds buf ;
int flag = 0 ;
int pid ;
shmid = shmget(IPC_PRIVATE, SIZE, IPC_CREAT|0600 ) ;
if ( shmid < 0 )
{
perror("get shm ipc_id error") ;
return -1 ;
}
pid = fork() ;
if ( pid == 0 )
{
shmaddr = (char *)shmat( shmid, NULL, 0 ) ;
if ( (int)shmaddr == -1 )
{
perror("shmat addr error") ;
return -1 ;
}
strcpy( shmaddr, "Hi, I am child process!\n") ;
shmdt( shmaddr ) ;
return 0;
} else if ( pid > 0) {
sleep(3 ) ;
flag = shmctl( shmid, IPC_STAT, &buf) ;
if ( flag == -1 )
{
perror("shmctl shm error") ;
return -1 ;
}
printf("shm_segsz =%d bytes\n", buf.shm_segsz ) ;
printf("parent pid=%d, shm_cpid = %d \n", getpid(), buf.shm_cpid ) ;
printf("chlid pid=%d, shm_lpid = %d \n",pid , buf.shm_lpid ) ;
shmaddr = (char *) shmat(shmid, NULL, 0 ) ;
if ( (int)shmaddr == -1 )
{
perror("shmat addr error") ;
return -1 ;
}
printf("%s", shmaddr) ;
shmdt( shmaddr ) ;
shmctl(shmid, IPC_RMID, NULL) ;
}else{
perror("fork error") ;
shmctl(shmid, IPC_RMID, NULL) ;
}
return 0 ;
}
編譯 gcc shm.c –o shm。
執行 ./shm,執行結果如下:
shm_segsz =1024 bytes
shm_cpid = 9503
shm_lpid = 9504
Hi, I am child process!
2、多程序讀寫範例
多程序讀寫即一個程序寫共享記憶體,一個或多個程序讀共享記憶體。下面的例子實現的是一個程序寫共享記憶體,一個程序讀共享記憶體。
(1)下面程式實現了建立共享記憶體,並寫入訊息。
shmwrite.c原始碼如下:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
typedef struct{
char name[8];
int age;
} people;
int main(int argc, char** argv)
{
int shm_id,i;
key_t key;
char temp[8];
people *p_map;
char pathname[30] ;
strcpy(pathname,"/tmp") ;
key = ftok(pathname,0x03);
if(key==-1)
{
perror("ftok error");
return -1;
}
printf("key=%d\n",key) ;
shm_id=shmget(key,4096,IPC_CREAT|IPC_EXCL|0600);
if(shm_id==-1)
{
perror("shmget error");
return -1;
}
printf("shm_id=%d\n", shm_id) ;
p_map=(people*)shmat(shm_id,NULL,0);
memset(temp, 0x00, sizeof(temp)) ;
strcpy(temp,"test") ;
temp[4]='0';
for(i = 0;i<3;i++)
{
temp[4]+=1;
strncpy((p_map+i)->name,temp,5);
(p_map+i)->age=0+i;
}
shmdt(p_map) ;
return 0 ;
}
(2)下面程式實現從共享記憶體讀訊息。
shmread.c原始碼如下:
#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
typedef struct{
char name[8];
int age;
} people;
int main(int argc, char** argv)
{
int shm_id,i;
key_t key;
people *p_map;
char pathname[30] ;
strcpy(pathname,"/tmp") ;
key = ftok(pathname,0x03);
if(key == -1)
{
perror("ftok error");
return -1;
}
printf("key=%d\n", key) ;
shm_id = shmget(key,0, 0);
if(shm_id == -1)
{
perror("shmget error");
return -1;
}
printf("shm_id=%d\n", shm_id) ;
p_map = (people*)shmat(shm_id,NULL,0);
for(i = 0;i<3;i++)
{
printf( "name:%s\n",(*(p_map+i)).name );
printf( "age %d\n",(*(p_map+i)).age );
}
if(shmdt(p_map) == -1)
{
perror("detach error");
return -1;
}
return 0 ;
}
(3)編譯與執行
① 編譯gcc shmwrite.c -o shmwrite。
② 執行./shmwrite,執行結果如下:
key=50453281
shm_id=688137
③ 編譯gcc shmread.c -o shmread。
④ 執行./shmread,執行結果如下:
key=50453281
shm_id=688137
name:test1
age 0
name:test2
age 1
name:test3
age 2
⑤ 再執行./shmwrite,執行結果如下:
key=50453281
shmget error: File exists