Linux共有メモリ
4491 ワード
Linuxの下でメモリを共有するのはmmapとSystem Vの2つの方式があります
1.mmap()システム呼び出しにより、プロセス間で同じ一般ファイルをマッピングすることによって共有メモリが実現される.通常ファイルがプロセスアドレス空間にマッピングされると、プロセスはread()、write()などの操作を呼び出すことなく、通常メモリにアクセスするようにファイルにアクセスできます.このことから,mmapは単に共有メモリを実現するために設計されたものではない.
2.System V共有メモリは、特殊なファイルシステムshmのファイルをマッピングすることによってプロセス間の共有メモリ通信を実現する.すなわち、すべての共有データを共有メモリ領域に配置する.このデータにアクセスするプロセスは、共有データを格納する物理メモリページをマッピングするために、本プロセスのアドレス空間にメモリ領域を追加しなければならない.
両者は応用上,大きな違いはなく,1つは通常のファイルを操作することであり,1つは操作交換パーティション上のshmファイルシステムである.
1.mmap方式
書き込みプロセス:
リードプロセス
2.System V方式
System V APIは比較的簡潔で,shmget(),shmmat(),shmmdt(),shmctrl()の4つの関数にのみ関与し,信号量関数の命名と一致した.
詳細については、以下を参照してください.
http://www.ibm.com/developerworks/cn/linux/l-ipc/part5/index1.html
http://www.ibm.com/developerworks/cn/linux/l-ipc/part5/index2.html
1.mmap()システム呼び出しにより、プロセス間で同じ一般ファイルをマッピングすることによって共有メモリが実現される.通常ファイルがプロセスアドレス空間にマッピングされると、プロセスはread()、write()などの操作を呼び出すことなく、通常メモリにアクセスするようにファイルにアクセスできます.このことから,mmapは単に共有メモリを実現するために設計されたものではない.
2.System V共有メモリは、特殊なファイルシステムshmのファイルをマッピングすることによってプロセス間の共有メモリ通信を実現する.すなわち、すべての共有データを共有メモリ領域に配置する.このデータにアクセスするプロセスは、共有データを格納する物理メモリページをマッピングするために、本プロセスのアドレス空間にメモリ領域を追加しなければならない.
両者は応用上,大きな違いはなく,1つは通常のファイルを操作することであり,1つは操作交換パーティション上のshmファイルシステムである.
1.mmap方式
書き込みプロセス:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#define SHMNAME "shm_ram"
#define OPEN_FLAG O_RDWR|O_CREAT
#define OPEN_MODE 00777
#define FILE_SIZE 4096*4
int main(int argc,char **argv)
{
int ret = -1;
int fd = -1;
void* add_w = NULL;
//
fd = shm_open(SHMNAME, OPEN_FLAG, OPEN_MODE);
if(-1 == (ret = fd))
{
perror("shm failed: ");
return ret;;
}
//
ret = ftruncate(fd, FILE_SIZE);
if(-1 == ret)
{
perror("ftruncate");
return ret;;
}
//
add_w = mmap(NULL, FILE_SIZE, PROT_WRITE, MAP_SHARED, fd, SEEK_SET);
if(NULL == add_w)
{
perror("mmap");
return ret;;
}
// memcpy
memcpy(add_w, "howaylee", sizeof("howaylee"));
//
ret = munmap(add_w, FILE_SIZE);
if(-1 == ret)
{
perror("munmap add_w faile: ");
return ret;;
}
//
/*shm_unlink(SHMNAME);
if(-1 == ret)
{
perror("shm_unlink faile: ");
return ret;;
}*/
}
リードプロセス
int main(int argc,char **argv)
{
int ret = -1;
int fd = -1;
char buf[4096] = {0};
void* add_r = NULL;
//
fd = shm_open(SHMNAME, OPEN_FLAG, OPEN_MODE);
if(-1 == (ret = fd))
{
perror("shm");
return ret;
}
//
ret = ftruncate(fd, FILE_SIZE); // 16k
if(-1 == ret)
{
perror("ftruncate");
return ret;
}
//
add_r = mmap(NULL, FILE_SIZE, PROT_READ, MAP_SHARED, fd, SEEK_SET);
if(NULL == add_r)
{
perror("mmap");
return ret;
}
// memcpy
memcpy(buf, add_r, sizeof(buf));
printf("buf = %s
", buf);
//
ret = munmap(add_r, FILE_SIZE);
if(-1 == ret)
{
perror("munmap");
return ret;
}
}
2.System V方式
System V APIは比較的簡潔で,shmget(),shmmat(),shmmdt(),shmctrl()の4つの関数にのみ関与し,信号量関数の命名と一致した.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MY_SHM_ID 0x00004589
#define IPC_BUF_SIZE 1*1024*1024
pthread_mutex_t mutex;
bool WriteShmMsg(const char *szMsg)
{
if(pthread_mutex_init(&mutex,NULL)!=0)
{
printf(" :
");
return false;
}
//
if((shmid=shmget(MY_SHM_ID,IPC_BUF_SIZE,0600|IPC_CREAT))<0)
{
perror("shmget");
return false;
}
void *mem;
//
if((mem=shmat(shmid,0,0))==(void*)-1)
{
perror("shmat");
return false;
}
sprintf((char*)mem,"%s",szMsg); //
shmdt(mem); //
pthread_mutex_unlock(&mutex);
return true;
}
詳細については、以下を参照してください.
http://www.ibm.com/developerworks/cn/linux/l-ipc/part5/index1.html
http://www.ibm.com/developerworks/cn/linux/l-ipc/part5/index2.html