- ベストアンサー
複数の共有メモリの作成
同じPC内に複数の共有メモリを作ろうとしています。自分の考えでは共有メモリを作成するときに shmget(key_t key, int size, int shmflg) のkeyを変えれば複数の共有メモリを作れると思ったのですがうまくいきません。ちなみにkeyは key = ftok(const char *pathname, int proj_id); で取得していて、pathnameとproj_idを変えればkey_tの値も変わり、複数の共有メモリが確保できると思ったのですが・・・。 また、ipcsで確認したところできた共有メモリのキーが0xffffffffになっているのも気になりました。普通は0x00000000になるべきなんでしょうか?
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
#3です。 > ftok():No such file or directory 「ファイルかディレクトリがない」というメッセージです。 ftok()でこのメッセージに関係するところといったらファイル名が思いつきませんか? > ("host"のところを'host'に変更) いえいえ違います! ' 'で文字列を指定していることが間違っているという指摘です。 proj_idはint型なので文字列"abc"でなく、文字'a'としないと駄目ということです。 " "と' 'で囲む意味と違いを考えてください。 # × int a = "abc"; # × int a = 'abc'; # ○ int a = 'a'; もちろん、int型なので > (#define PROJ_CHAR 7としました) は、間違いではありません。 >int ftok ( string pathname, string proj ) プラットフォームによる違いです。第二引数がchar型という環境もあります。 で、いろいろと思考錯誤が入ったと思いますが、質問当初に頭をリセットしてください。 key = ftok(KEYFILE_PATH, PROJ_CHAR); がどうなれば良いかというと key = ftok("host", 'a'); の形になれば良いです。 これで「ftok():No such file or directory」のエラーが出るようであれば、ファイルの置かれている場所へのパスが通ってないということなので、ファイルを見つけられるようにパス指定を変えれば良いだけです。 実行形式mainと同じ場所にhostファイルがあるなら、"./host"とするとか、フルパス指定にするとかです。
その他の回答 (3)
- pareopara
- ベストアンサー率100% (7/7)
現状はftok()が失敗して-1を返してきていると思われます。 毎回key=-1でshmget()していれば同じ結果になるのは当然ですよね。 まずはkeyの値を確認してみてください。 その後、#2さんが気にされている箇所を修正してみては如何でしょうか。 # int型に渡すので文字列は間違いということは分かりますよね? # 定義をじっくり見てください。文字列が''で囲まれています。だからといって # 早まって""に直さないでください。 # 要は'a'みたいに文字を定義してください。
補足
えと結果から言うと全然うまくいきませんでした。 まず今まで指摘されたことを直しました。 いままではエラーのときの対応をしていなかったのでkeyの指定のところにエラーの対応を入れました。 key = ftok(KEYFILE_PATH, PROJ_CHAR) if(key == -1){ perror("ftok()"); return 1; } それでまず第二引数をint型に直したところ (#define PROJ_CHAR 7としました) 問題なくコンパイルが通ったのでいけるかなと思い実行してみると ftok():No such file or directory このエラーはどういうエラーなのでしょうか? またこの状態でpareoraraさんが指摘されていた文字列指定のところを直したところ ("host"のところを'host'に変更) 警告:複数文字からなる文字定数 警告:引数1個の'ftok'を渡しますにより、キャストなしで整数からポインタを作りました とでて、実行したところ ftok():Bad address と出てしまいました。ここでいう整数からポインタを作るとはどういう意味なのでしょうか? また、自分で色々調べたところftokには int ftok ( string pathname, string proj ) という引数指定があるようなのですがこれは key_t ftok(const char *pathname, int proj_id); とは全く別のものなのでしょうか? 多々質問してしまって申し訳ありません。ご指導お願いします。
- terra5
- ベストアンサー率34% (574/1662)
>複数作るときはftokの引数を変えているだけなんですがこれではだめなのでしょうか? 具体的に何を指定したか書いてください。 >実際に実行すると一つ目はうまくいくのですが二つ目になると Can't Access to the shared memory と出てしまいます。 具体的にどうやっていますか。 単一プログラム中で shm_initialize()を複数呼び出している、別プログラムでパラメタを変えて複数起動している、同一のプログラムを二つ起動している等。 使い方を誤解されているのかも。 ざっと見たところ key = ftok(KEYFILE_PATH, PROJ_CHAR); ですが、多分 key_t ftok(const char *pathname, int proj_id); なのに、 #define PROJ_CHAR (char) 'dbhost' が気になります。
補足
返信遅れてしまってすみません。 えっと使い方なんですが前に載せたプログラム(shm.h shm.c main.c)を違うディレクトリにおいてftokの引数であるpathnameとproj_idだけを変えて使おうとしています。(つまりpathnameとproj_idの部分だけが違うプログラムを違うディレクトリにおいて複数の共有メモリを作ろうとしています) >ざっと見たところ key = ftok(KEYFILE_PATH, PROJ_CHAR); ですが、多分 key_t ftok(const char *pathname, int proj_id); なのに、 #define PROJ_CHAR (char) 'dbhost' が気になります。 確かに・・。ここはint型にしたほうがいいですよね。 でもint型にしても出来ませんでした・・・。 それで今、ftokを使わずにkeyを無理やり自分で設定したら複数できました・・・。(key = 1とか無理やりkeyを決める) でもこれってまずいですよね?
- terra5
- ベストアンサー率34% (574/1662)
OSは? うまくいかないとは、どういう状態か? 詳しく具体的に。 考え方自体はあっているように思えますので、実際のコードに何か問題があるように思えます。 また、shmgetだけでは共有メモリ・セグメントの識別子を返すだけですから、これだけでは使用可能な共有メモリができていないことは分ってますよね?
補足
OSはRedhatlinux8です。ソースは以下のような感じです。shm.cで初期化、アクセス、消去の関数を作って cc -o main main.c shm.c でコンパイルして使っています。 複数作るときはftokの引数を変えているだけなんですがこれではだめなのでしょうか?実際に実行すると一つ目はうまくいくのですが二つ目になると Can't Access to the shared memory と出てしまいます。 -----SHM.h---------------- #ifndef __SHM_H__ #define __SHM_H__ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/msg.h> #define SHM PARAM KEY 0x1000 #define KEYFILE_PATH "host" #define PROJ_CHAR (char) 'dbhost' #define FIN (255) struct SHM_PARAM{ int shd_param_id; int status; int a; int b; int c; }; #endif /* __SHM_H__ */ extern int shm_initialize(key_t shm_key, int shm_size, int *shrd_id, int *shm_ptr); extern int shm_access(key_t shm_key, int shm_size, int *shrd_id, int *shm_ptr); extern int erase_shm(struct SHM_PARAM *pram_ptr); -------SHM.c------ #include "shm.h" int shm_initialize( key_t shm_key, /*共有メモりの為のキーワード*/ int shm_size, /*共有メモりのサイズ*/ int *shrd_id, /*共有メモりIDへのポインタ*/ int *shm_ptr) /*共有メモりの先頭アドレスへのポインタ*/ { /*現状態へのアクセス*/ *shrd_id = shmget(shm_key, shm_size, IPC_CREAT|0666); if(*shrd_id < 0){ printf("[shm_initialize]:Can't Access to the shared memory!!\n"); return -1; } *shm_ptr = (int)shmat( *shrd_id, NULL, 0); memset((void*)*shm_ptr, 0, shm_size); /*終了*/ return ( *shrd_id); } int shm_access( key_t shm_key, int shm_size, int *shrd_id, int *shm_ptr) { *shrd_id = shmget(shm_key, shm_size, 0444); if( *shrd_id < 0){ printf("Can't Access to the shared memory!!\n"); return (-1); } *shm_ptr = (int)shmat( *shrd_id,(const void*)NULL, 0); return ( *shrd_id); } int erase_shm(struct SHM_PARAM *param_ptr) { shmctl(param_ptr->shd_param_id, IPC_RMID, 0); return (0); } ---main.c--- #include "shm.h" int shd_param_id; /*共有メモりのID*/ struct SHM_PARAM *param_ptr; /*共有パラメータへのポインタ*/ key_t key; int main(int argc, char **argv) { int i; key = ftok(KEYFILE_PATH, PROJ_CHAR); shm_initialize(key, sizeof(struct SHM_PARAM), &shd_param_id, (int *)¶m_ptr); param_ptr->shd_param_id = shd_param_id; printf("Memory attaced at %x \n", (int)param_ptr); printf("a=%d\n",param_ptr->a); printf("b=%d\n",param_ptr->b); printf("c=%d\n",param_ptr->c); //erase_shm(param_ptr); // param_ptr->status = FIN; return 0; }
お礼
やっと理解できました。 丁寧に解説していただいてありがとうございます。