linux共有メモリ

7712 ワード

                              (                     )              。 GNU/Linux                   ,           API              。                   。           。          ,             ,                       ,                     。                   。
                   ,          ,          。
    ,     GNU/Linux         IPC  。
                        ,                 
    shmdt     。
    ,                ,                        。
              (    IPC——RMID    shmctl),          0,
           。

linuxでは、上記の機能を完了するための4つの関数が用意されています.
1、shmget
     
shmget(共有メモリ識別子を取得するか、共有メモリオブジェクトを作成する)
必要なヘッダファイル
#include
#include
関数の説明
共有メモリ識別子を取得するか、共有メモリオブジェクトを作成して共有メモリ識別子を返します.
関数プロトタイプ
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:コアメモリ不足
//          ,        ,          
#include 
#include   //getpagesize(  )
#include 
#include 

#define MY_SHM_ID 67483

int main()
{
	//            
	printf( "page size=%d
",getpagesize( ) ); // int shmid,ret; /*IPC( , , ) IPC_CREAT IPC_EXCL 。 : IPC_CREAT , ID, , ID, IPC_EXCL , ,shmget() -1 IPC_CREAT | IPC_EXCL , , , ID。 , -1;*/ shmid=shmget( MY_SHM_ID,4096,0666|IPC_CREAT ); // 4KB 。 // if( shmid>0 ) printf( "Create a shared memory segment %d
",shmid ); // struct shmid_ds shmds; shmid=shmget( MY_SHM_ID,0,0 );// printf("shmid = %d
", shmid); ret=shmctl( shmid, IPC_STAT, &shmds ); if( ret==0 ) { printf( "Size of memory segment is %d
",shmds.shm_segsz ); printf( "Numbre of attaches %d
",( int )shmds.shm_nattch ); } else { printf( "shmctl( ) call failed
" ); } // ret=shmctl( shmid,IPC_RMID,0 ); if( ret==0 ) printf( "Shared memory removed
" ); else printf( "Shared memory remove failed
" ); return 0; }

2、shmctl
 
shmctl(共有メモリ管理)
必要なヘッダファイル
#include
#include
関数の説明
共有メモリの制御を完了
関数プロトタイプ
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
関数の入力値
msqid
共有メモリ識別子
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:msqidの識別子を持つ共有メモリが削除されました
EINVAL:無効なパラメータcmdまたはshmid
EPERM:パラメータcmdがIPC_SETまたはIPC_RMID、実行権限が足りない
3、shmat
shmat(共有メモリ領域オブジェクトを呼び出しプロセスのアドレス空間にマッピングする)
必要なヘッダファイル
#include
#include
関数の説明
共有メモリ識別子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:コアメモリ不足
      例
#include 
#include 
#include 
#include 
#define MY_SHM_ID 67483
int main(  )
{
	//            
	int shmid,ret;
	void* mem;
	shmid=shmget( MY_SHM_ID,0,0 );
	if( shmid>=0 )
	{
		mem=shmat( shmid,( const void* )0,0 );
		
		//shmat()                
		if( ( int )mem!=-1 )
		{
			printf( "Shared memory was attached in our address space at %p/n",mem );
			
			//           
			strcpy( ( char* )mem,"This is a test string./n" );
			printf( "%s/n",(char*)mem );
			//        
			ret=shmdt( mem );
			if( ret==0 )
				printf( "Successfully detached memory /n" );
			else
				printf( "Memory detached failed %d/n",errno );
		}
		else
			printf( "shmat(  ) failed/n" );
		
	}
	else
		printf( "shared memory segment not found/n" );
	return 0;
}

4、shmdt
shmdt(共有メモリ接続を解除)
必要なヘッダファイル
#include
#include
関数の説明
shmat関数とは逆に、共有メモリのアタッチメントポイントを切断するためのアドレスであり、このプロセスがこの共有メモリにアクセスすることを禁止します.
関数プロトタイプ
int shmdt(const void *shmaddr)
関数の入力値
shmaddr:接続された共有メモリの開始アドレス
関数の戻り値
成功:0
エラー:-1、エラー原因errorに保存
追加の説明
この関数呼び出しは、指定した共有メモリ領域を削除するのではなく、shmat関数で接続した共有メモリを現在のプロセスから削除するだけです.
エラーコード
EINVAL:無効なパラメータshmaddr
読み書きテスト
 
./write.h
#include 
#include 
#include 
#include 
#include 
#include 

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
",key) ; shm_id=shmget(key,4096,IPC_CREAT|IPC_EXCL|0600); if(shm_id==-1) { perror("shmget error"); return -1; } printf("shm_id=%d
", 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 ; }

./read.h
#include 
#include 
#include 
#include 
#include 
#include 
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
", key) ; shm_id = shmget(key,0, 0); if(shm_id == -1) { perror("shmget error"); return -1; } printf("shm_id=%d
", shm_id) ; p_map = (people*)shmat(shm_id,NULL,0); for(i = 0;i<3;i++) { printf( "name:%s
",(*(p_map+i)).name ); printf( "age %d
",(*(p_map+i)).age ); } if(shmdt(p_map) == -1) { perror("detach error"); return -1; } return 0 ; }