プロセス間通信(IPC)メソッド(B)
共有メモリ(SHAREのMEMORY)
- 複数のプロセスが直接同じメモリ空間を読み書きすることができことができ、それが可能なIPCの最速の形です。他の通信機構のための効率的な設計ではありません。
- 複数のプロセス間で情報を交換するために、カーネルは、プロセスによってアクセス可能なメモリ領域の一部を取っておくには、独自のプライベートアドレス空間にマッピングされる必要があります。このプロセスは、直接大幅に効率を向上させる、データのコピーを必要とせずにメモリを読み書きすることができます。
- 複数のプロセスは、いくつかのメモリを共有し、したがって、プロセス間の同期や相互排除を達成するために(例えば、セマフォなど)同期機構のいくつかの種類に依存する必要がするからです。
Linuxカーネルは、このようなのmmap()システムコール、Posixの共有メモリー、およびSystem Vの共有メモリとして、共有メモリのさまざまなをサポートしています。
mmap
MMAP()システムコールは、共通のファイルにマッピングすることにより、共有メモリとの間の処理を可能にします。一般的なファイルは、プロセスのアドレス空間にマップされた後、プロセスはファイルに通常のメモリアクセスと同様にアクセスすることができ、)(読み取りを呼び出す必要はありません、(書き込み)など。
注意:実際には、MMAP()システムコールは完全に共有メモリや設計に使用されていません。それ自体は一般的なファイルへの一般的なアクセスは異なる方法を提供しますが、プロセスは、メモリのように読んで、通常のファイルに書き込み操作をすることができます。PosixまたはSystem V共有メモリIPCは、共有のために純粋であり、当然のmmap()は、共有メモリは、その主な応用の一つです。
MMAPの使用
#include <sys/mman.h>
void *mmap(void *adrr, size_t length, int prot, int flags, int fd, off_t offset);
- 戻り値:成功:作成された最初のアドレスのマッピング領域を返し、失敗:MAP_FAILEDマクロ
- パラメータ:
- ADDR:Linuxカーネルによって指定された最初のアドレスのマッピング領域の確立、。使用に際しては、パススルーNULL
- 長さ:マップ領域のサイズを作成するには
- PROT:マッピング領域の権威PROT_READ、PROT_WRITE、PROT_READ | PROT_WRITE
- フラグ:フラグパラメータ(多くの場合、更新物理領域を設定し、共有を設定し、匿名のマッピング領域を作成するために使用されます)
- MAP_SHARED:あなたがマップされたどのような領域は、物理デバイス(ディスク)に反映されます。
- MAP_PRIVATE:マッピング領域を変更は、物理デバイスに反映されていません。
- FD:マッピング領域を構築するために使用されるファイルディスクリプタ
- オフセット:オフセットマップファイルを(4kの整数倍)
同様のアプリケーションのメモリ空間を持つmalloc関数、使用終了後に確立のmmapマッピングされた地域でも同様のフリー機能を解放するために呼び出す必要があります。
int munmap(void *addr, size_t length); //成功:0; 失败:-1
例えば。
// 写共享内存
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
typedef struct
{
char name[32];
int age;
} people;
int main(int argc, char** argv)
{
if(argc < 2)
{
fprintf(stderr,"Usage: %s filename \n", argv[0]);
return -1;
}
people* p_map;
char temp = 'a';
int fd = open(argv[1], O_CREAT|O_RDWR|O_TRUNC, 00777);
if (-1 == fd)
{
printf("open file error = %s\n", strerror(errno));
return -1;
}
ftruncate(fd, sizeof(people)*10);
p_map = (people*)mmap(NULL, sizeof(people)*10, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (MAP_FAILED == p_map)
{
printf("mmap file error = %s\n", strerror(errno));
return -1;
}
for(int i = 0; i < 10; i++)
{
memcpy( (*(p_map+i)).name, &temp, 1);
(*(p_map+i)).name[1] = 0;
(*(p_map+i)).age = 20+i;
temp += 1;
}
printf("initialize over\n");
close(fd);
munmap(p_map, sizeof(people)*10);
printf("umap ok \n");
return 0;
}
// 读共享内存
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
typedef struct
{
char name[32];
int age;
} people;
int main(int argc, char** argv)
{
if(argc < 2)
{
fprintf(stderr,"Usage: %s filename \n", argv[0]);
return -1;
}
people* p_map;
struct stat filestat;
int fd = open(argv[1], O_CREAT|O_RDWR, 00777);
if (-1 == fd)
{
printf("open file error = %s\n", strerror(errno));
return -1;
}
fstat(fd, &filestat);
p_map = (people*)mmap(NULL, filestat.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (MAP_FAILED == p_map)
{
printf("mmap file error = %s\n", strerror(errno));
return -1;
}
for(int i = 0; i < 10; i++)
{
printf("name = %s, age = %d\n",(*(p_map+i)).name, (*(p_map+i)).age);
}
close(fd);
munmap(p_map, sizeof(people)*10);
printf("umap ok \n");
return 0;
}
結果:
执行./mmap_w people.txt
执行./mmap_r people.txt
POSIX共有メモリ
メソッドを使用してPOSIX共有メモリは、次の2つのステップがあります。
shm_open
POSIX共有メモリ・オブジェクトを作成または開きます- するために呼び出す
mmap
現在のプロセスのアドレス空間にマッピング
そして、メモリマップドファイルディスクリプタのmmap違いによる通信を使用すると、同じ取得パラメータではありません:オープンまたは場合、shm_openて。特性を有するセマフォとして知られているPOSIX POSIXメッセージキューと共有メモリは、カーネルとの持続的です。
POSIX共有メモリ使用量
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
// 打开一个共享内存的文件句柄
int shm_open(const char *name, int oflag, mode_t mode);
//注意 这里的名字具有形式 /somename,即必须以 / 为开头,因为POSIX共享内存对应的文件是位于/dev/shm这个特殊的文件系统内。
// 删除一个共享内存的名字,但只有所有程序都关闭,才会真的删除
int shm_unlink(const char *name);
例えば。
共有メモリを書きます
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
typedef struct
{
char name[32];
int age;
} people;
main(int argc, char** argv)
{
if(argc < 2)
{
fprintf(stderr,"Usage: %s /filename \n", argv[0]);
return -1;
}
people* p_map;
char temp = 'a';
int fd = shm_open(argv[1], O_CREAT|O_RDWR, 00777);
if (-1 == fd)
{
printf("open file error = %s\n", strerror(errno));
return -1;
}
ftruncate(fd, sizeof(people)*10);
p_map = (people*)mmap(NULL, sizeof(people)*10, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (MAP_FAILED == p_map)
{
printf("mmap file error = %s\n", strerror(errno));
return -1;
}
for(int i = 0; i < 10; i++)
{
memcpy( ( *(p_map+i) ).name, &temp, 1);
( *(p_map+i) ).name[1] = 0;
( *(p_map+i) ).age = 20+i;
temp += 1;
}
printf("initialize over\n");
close(fd);
munmap(p_map, sizeof(people)*10);
printf("umap ok \n");
return 0;
}
共有メモリを読みます
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
typedef struct
{
char name[32];
int age;
} people;
main(int argc, char** argv)
{
if(argc < 2)
{
fprintf(stderr,"Usage: %s /filename \n", argv[0]);
return -1;
}
people* p_map;
struct stat filestat;
int fd = shm_open(argv[1], O_CREAT|O_RDWR, 00777);
if (-1 == fd)
{
printf("open file error = %s\n", strerror(errno));
return -1;
}
fstat(fd, &filestat);
p_map = (people*)mmap(NULL, filestat.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (MAP_FAILED == p_map)
{
printf("mmap file error = %s\n", strerror(errno));
return -1;
}
for(int i = 0; i < 10; i++)
{
printf("name = %s, age = %d\n",(*(p_map+i)).name, (*(p_map+i)).age);
}
close(fd);
munmap(p_map, sizeof(people)*10);
printf("umap ok \n");
return 0;
}
共有メモリを削除します。
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
main(int argc, char** argv)
{
if(argc < 2)
{
fprintf(stderr,"Usage: %s /filename \n", argv[0]);
return -1;
}
int ret = shm_unlink(argv[1]);
if (-1 == ret)
{
printf("unlink shm error = %s\n", strerror(errno));
return -1;
}
printf("unlink ok \n");
return 0;
}
結果:
[root@rocket ipc]# g++ -g -o ipc_posix_mmap_writer ipc_posix_mmap_writer.cpp -lrt
[root@rocket ipc]# ./ipc_posix_mmap_writer /shm_from_mem.txt
initialize over
umap ok
[root@rocket ipc]# g++ -g -o ipc_posix_mmap_reader ipc_posix_mmap_reader.cpp -lrt
[root@rocket ipc]# ./ipc_posix_mmap_reader /shm_from_mem.txt
name = a, age = 20
name = b, age = 21
name = c, age = 22
name = d, age = 23
name = e, age = 24
name = f, age = 25
name = g, age = 26
name = h, age = 27
name = i, age = 28
name = j, age = 29
umap ok
[root@rocket ipc]# ./ipc_posix_mmap_unlink /shm_from_mem.txt
unlink ok
[root@rocket ipc]# ./ipc_posix_mmap_unlink /shm_from_mem.txt
unlink shm error = No such file or directory
[root@rocket ipc]# ll /dev/shm/|grep mem
[root@rocket ipc]#
System V共有メモリ
システムコールはmmap()通常のファイルをマッピングすることにより、共有メモリ。System V共有メモリは、特殊なファイルシステムSHMにおけるプロセス間通信マップファイルを介してです。すなわち、(shmid_kernel構造によって連結された)ファイルシステムSHMにおける特殊ファイルに対応するそれぞれの共有メモリ領域です。プロセス間でデータを共有する必要性がIPC共有メモリ領域内に配置されているすべてが移動するには、このプロセスのアドレス空間を共有する地域をマッピングすることであるべきプロセスの共有領域へのアクセスを必要とする、場所と呼ばれます。共有メモリシステムV IPCを得るまたは共有メモリ領域を作成し、そしてたshmgetによって対応する識別子を返します。取得または保証でカーネルは、共有メモリ領域を作成すると同時にノートshmid_kernel構造で適切な共有メモリ領域を初期化するだけでなく、特別なSHMファイルシステムでは、作成し、同じ名前のファイルを開いて、メモリ内の対応するファイルを確立するたshmget dentryとinode構造体は、新しくオープンしたファイルは、(任意のプロセスは、共有メモリ領域にアクセスすることができる)任意のプロセスに属していません。このすべてがたshmgetシステムコールを行います。
各ゾーンは、共有メモリ制御構造の構造体shmid_kernelを有し、共有メモリ領域がブリッジに格納されたデータ構造に非常に重要であり、ファイルシステムの管理は、以下のように定義され、結合shmid_kernel。
struct shmid_kernel /* private to the kernel */
{
struct kern_ipc_perm shm_perm;
struct file* shm_file;
int id;
unsigned long shm_nattch;
unsigned long shm_segsz;
time_t shm_atim;
time_t shm_dtim;
time_t shm_ctim;
pid_t shm_cprid;
pid_t shm_lprid;
};
ドメインの中で最も重要な構造は、アドレスがファイルをマッピングされます格納、shm_fileでなければなりません。共有メモリモードをながら、ファイルシステムのSHMの特定のファイルに対応する各共有オブジェクトのメモリ領域は、通常の状況下では、特殊なファイルシステムSHMファイルは、等にアクセスするためのリード()、write()メソッドで使用されていませんプロセスのアドレス空間にマッピングされたファイルの後に、直接そのメモリアクセスのアクセスに使用することができます。
カーネルデータ構造、システム内のすべての共有メモリ領域を維持することにより、構造体ipc_idsのshm_ids。shm_ids.entries上図は、変数は構造配列を指すipc_id、各アレイは構造ipc_id kern_ipc_perm点ポインタ構造を有しています。ここでシステムV共有メモリ領域について、読者に精通している必要がありkern_ipc_permホストがshmid_kernelは、カーネルは、すべてのシステムの共有領域を制御することができるように、共有メモリの領域を記述するために使用される、shmid_kernel構造です。一方、ファイルに対応するファイルシステムのSHM shm_fileを指すファイルタイプshmid_kernelポインタの構成では、ファイルシステム内のSHMファイルに対応付けて共有メモリ領域に、そのように。
共有メモリ領域を作成した後、システムがこの関数にshmat()を完了するために呼び出し、プロセスのアドレス空間にマップされなければなりません。あなたは()たshmgetを呼び出したときに、対応するメモリ領域を共有ファイルシステムSHMと同じ名前のファイルを作成しているので、それゆえ、にshmat()を呼び出しは(同じプロセスでファイルシステムSHMとして名、原則とmmapマッピングファイルの処理に相当します)に類似。
System V共有メモリ使用量
#include <sys/ipc.h>
#include <sys/shm.h>
// 获取共享内存区域
int shmget(key_t key, size_t size, int shmflg);
// 连接共享内存区域
void *shmat(int shmid, const void *shmaddr, int shmflg);
// 断开共享内存区域
int shmdt(const void *shmaddr);
// 对共享内存区域进行控制
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
// 将path和proj_id转换成System V IPC key
key_t ftok(const char *pathname, int proj_id);
例えば。
共有メモリを書きます
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
typedef struct
{
char name[32];
int age;
} people;
int main(int argc, char** argv)
{
int shm_id,i;
key_t key;
people* p_map;
char temp = 'a';
const char* name = "/dev/shm/my_systemv_shm1";
key = ftok(name,0);
if (key == -1)
{
perror("ftok error");
return -1;
}
shm_id=shmget(key, 4096, IPC_CREAT);
if(shm_id == -1)
{
perror("shmget error");
return -1;
}
p_map=(people*)shmat(shm_id,NULL,0);
for(int i = 0; i < 10; i++)
{
memcpy( ( *(p_map+i) ).name, &temp, 1);
( *(p_map+i) ).name[1] = 0;
( *(p_map+i) ).age = 20+i;
temp += 1;
}
printf("initialize over\n");
if(shmdt(p_map) == -1)
{
perror(" detach error ");
return -1;
}
return 0;
}
共有メモリを読みます
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
typedef struct
{
char name[32];
int age;
} people;
int main(int argc, char** argv)
{
int shm_id,i;
key_t key;
people* p_map;
const char* name = "/dev/shm/my_systemv_shm1";
key = ftok(name,0);
if (key == -1)
{
perror("ftok error");
return -1;
}
shm_id=shmget(key, 4096, IPC_CREAT);
if(shm_id == -1)
{
perror("shmget error");
return -1;
}
p_map=(people*)shmat(shm_id,NULL,0);
for(int i = 0; i < 10; i++)
{
printf( "name:%s, ",(*(p_map+i)).name );
printf( "age %d\n",(*(p_map+i)).age );
}
if(shmdt(p_map) == -1)
{
perror(" detach error ");
return -1;
}
return 0;
}
結果:
[root@rocket ipc]# g++ -g -o ipc_systemv_mmap_writer ipc_systemv_mmap_writer.cpp
[root@rocket ipc]# touch /dev/shm/my_systemv_shm1
[root@rocket ipc]# ./ipc_systemv_mmap_writer
initialize over
[root@rocket ipc]# g++ -g -o ipc_systemv_mmap_reader ipc_systemv_mmap_reader.cpp
[root@rocket ipc]# ./ipc_systemv_mmap_reader
name:a, age 20
name:b, age 21
name:c, age 22
name:d, age 23
name:e, age 24
name:f, age 25
name:g, age 26
name:h, age 27
name:i, age 28
name:j, age 29
观察一下共享内存:
[root@rocket ipc]# ./get_ipc_key /dev/shm/my_systemv_shm1
key = 1084739
[root@rocket ipc]# ipcs
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 0 gdm 600 393216 2 dest
0x00000000 32769 gdm 600 393216 2 dest
0x00000000 65538 gdm 600 393216 2 dest
0x00000000 98307 gdm 600 393216 2 dest
0x00108d43 131076 root 0 4096 0
看到我们新建的共享内存了吧?删除也很简单:
[root@rocket ipc]# ipcrm -m 131076
[root@rocket ipc]# ipcs
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 0 gdm 600 393216 2 dest
0x00000000 32769 gdm 600 393216 2 dest
0x00000000 65538 gdm 600 393216 2 dest
0x00000000 98307 gdm 600 393216 2 dest