合格昨日、Oracle データベースサーバの共有メモリ利用状況をipcsコマンドで確認 しました。実行画面の左から2列目(2カラム目)に宝石赤


    shmid


って表示されてマスネイル


 shmとは、SHared Memory=共有メモリ¥


shmidとIDがついて共有メモリのセグメント識別子いちご




Oracle サーバのプロセスが使用しているデータセグメント(キョウユウメモリ)の位置を示しているんだろナキャンディー

 このように、Oracleは共有メモリをつかっています虹

 解る人は別にはるかに教わりたかぁないか(*゚.゚)ゞ


゚・*:.。..。.:*・゚゚・*:.。..。.:*・゚ ゚・*:.。..。.:*・゚゚・*:.。..。.:*・゚



 さあ、お休みの今日のハルカわっ!! オラクルサーバちゃんがやっていることと同じようなことを、C言語でプログラミングしてみて、試しにやってみま~すっ!! 

                  環境はLinuxワンピース


 実験内容は


*:..。o○☆゚・:,。*:..。o○☆


①1つのプロセス(=簡易サーバ)を作って、

  そのプロセスで共有メモリ空間を獲得サンダル


②他のプロセスからそのメモリ空間の

  データにアクセスして、空間のデータを更新するリボン


          *:..。o○☆゚・:,。*:..。o○☆


ってゆぅ簡易データベースサーバ&クライアントですっ恋の矢



 まず①の共有メモリを使用するサーバのソース

shm_server.c指輪



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main(void)
{
  int id;
  char *adr;

  /* 新規shmを生成 */
  if((id = shmget (IPC_PRIVATE,512,IPC_CREAT|0666))==-1){
    perror ("shmget");
    exit(-1);
  }

  /* データセグメントにアタッチ */
  if((adr=(char *)shmat(id,NULL,0))==(void *)-1){
    perror("shmat");
  } else {
    strcpy(adr,"データ未登録");
    /* 1秒毎出力 */
    while(1) {
      printf("SHM_ID=%d::VALUE=%s\n",id,adr);
      /* end 入力で終了 */
      if (strcmp(adr,"end")==0) {
        break;
      }
      sleep(1);
    }
    if (shmdt(adr)==-1) {
      /* アンマップ */
      perror("shmdt");
    }
  }
  /* 共有メモリを削除 */
  if (shmctl(id,IPC_RMID,0)==-1){
    perror("shmctl");
    exit(EXIT_FAILURE);
  }
  return 0;
}



  共有メモリを使う方法は、王冠2


shmget()システムコールで、共有メモリのデータセグメント識別子を取得する。

shmat()システムコールで、自プロセスのデータセグメントにマップ(アタッチ)する。

shmdt()システムコールで、データセグメントをアンマップ(デタッチ)する。

shmctl()システムコールで、共有メモリを削除する


という流れ。前回用いたipcのヘッダファイルと、shm.hをincludeしてます~~

このプログラムは、

①で変数idにセグメント識別子を代入

②でデータセグメントにアタッチし

  変数adsにデータ本体を格納、表示しますぅ。。


                    *:..。o○☆゚・:,。*:..。o○☆


ドキドキおつぎは、クライアントを想定した、データ更新プログラム、

shm_writer.c


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main(int argc, char *argv[])
{
  int id;
  char *adr;

  if ( argc <= 2 ) {
    fprintf(stderr,"Usage:共有メモリID データ\n");
    exit(EXIT_FAILURE);
  }

  id=atoi(argv[1]);

  if((adr=(char *)shmat(id,0,0))==(void *)-1){
    perror("shmat");
  } else {
    strcpy(adr, argv[2]);
    fprintf(stderr,"written.\n");
    if(shmdt(adr)==-1){
      perror("shmdt");
    }
  }
}



 このプログラムは引数として与えられたセグメント識別子を指定して、shmat()、つまりサーバと同じ共有メモリのアドレス空間を指す、メモリを操作(更新)できるようになるわけドキドキ


゚・*:.。..。.:*・゚゚・*:.。..。.:*・゚ ゚・*:.。..。.:*・゚゚・*:.。..。.:*・゚

 あ~~んまり、はるかも、理解できていないと思うんだけどはてなマーク

……実際にタメシテミル爆弾


上の2つのプログラムをコンパイルしまぁす



> gcc shm_server.c -o shm_server
> gcc shm_writer.c -o shm_writer
>


簡易DBサーバを起動しまぁす~



> ./shm_server
SHM_ID=950285::VALUE=データ未登録
SHM_ID=950285::VALUE=データ未登録
SHM_ID=950285::VALUE=データ未登録
(後略)


 この時点では、共有メモリの識別子950285のデータセグメントには何のデータも登録されていない状態。。




ここで、別のターミナルを立ち上げて、

クライアント側書き込みプログラムを実行し、同じ共有メモリ識別子(950285)の空間に書き込みを行います。

つまり、別プロセスから他のプロセスのアドレス空間を操作する、ってことです。さぁぁぁぁぁてっ!ドンッ



> ./shm_writer 950285 ブラジャー
written.
>


こちら、サーバ側ターミナル。あ!データが変わった!!クラッカー



SHM_ID=950285::VALUE=ブラジャー
SHM_ID=950285::VALUE=ブラジャー
SHM_ID=950285::VALUE=ブラジャー
SHM_ID=950285::VALUE=ブラジャー
SHM_ID=950285::VALUE=ブラジャー


データが更新されてます!バナナ

さらにクライアント側から更新をかけるとぉぉ音譜



> ./shm_writer 950285 コルセット
written.


サーバ側



SHM_ID=950285::VALUE=コルセット
SHM_ID=950285::VALUE=コルセット
SHM_ID=950285::VALUE=コルセット
SHM_ID=950285::VALUE=コルセット
SHM_ID=950285::VALUE=コルセット
SHM_ID=950285::VALUE=コルセット
SHM_ID=950285::VALUE=コルセット

と、メモリ空間が共有されていること、よぉぉく、理解できましたぁっ!



゚・*:.。..。.:*・゚゚・*:.。..。.:*・゚ ゚・*:.。..。.:*・゚゚・*:.。..。.:*・゚


 なるほど、ねぇ。。。はるかこれは先輩のススメで、初めてやってみたのですが、なぁんだかぁ、データベースの基本的な仕組みがよぉくわかった気がするラーメン


 もっとlockとかセマフォとかが入ってきてややこしい仕組みだとは思うんだけどねっ、Oracleなんかは。。。(・ω・)/



ひっさびさに、チョー夢中になって実験しちゃいました



■関連記事:

共有メモリ☆そのいちっ★ipcsこまんど