• ベストアンサー

スレッド?

プロセス間で共有できるメモリの使い方を教えてください。 (システムコールshmget、shmat、shmdt以外で。) 使用例など有りましたら是非お願いします。

  • zukka
  • お礼率100% (5/5)

質問者が選んだベストアンサー

  • ベストアンサー
  • kaz-sugi
  • ベストアンサー率50% (3/6)
回答No.3

shmでメモリを共有した時に、プロセス数*共有メモリサイズを 使用するということはありません。 LinuxのOSとしてのメモリ管理の内部実装はよくは知りませんが、 今時のまっとうなUNIXであれば、共有メモリの実装は、 1つのメモリオブジェクトを複数のプロセスからポイントする、 というように実装されているかと思います。 普通の状態では、仮想アドレス空間から物理アドレス空間への 変換テーブルをプロセスごとユニークなものを持ちます。 メモリオブジェクトとはその変換テーブルを管理するOS内の資源の単位で、 おおざっぱに言えば、プロセスが使用するメモリ空間の、 テキスト領域(プログラムのコードを格納する領域)、 データ領域(グローバル変数を格納する領域)、スタック領域(ローカル 変数を格納する領域)、という単位でオブジェクトが作られます。 つまり、1プロセスにつき、この3種類の領域に対応する 3つのメモリオブジェクトへのポインタを持っていて、 それぞれのオブジェクトは変換テーブルを持ちます。 別プロセス間でメモリを共有するという状態は、 共有している領域へのメモリオブジェクトへのポインタが 同じメモリオブジェクトを指している状態であります。 ですから、メモリオブジェクトはまさに「共有/共用」されており、 プロセス数分メモリを消費するということはありません。 但し、わずかですが管理領域分はプロセス数分使うでしょう。。 あと、cloneで作成した子プロセスが親プロセスより先に終了すると ご指摘のとおりdefunct(ゾンビ)ができます。 こいつを消すには親がwaitしてあげるしかなさそうです。。。 signal(SIGCHLD, SIG_IGN)をしてみましたが、ダメでしたね。。。 pthread_createで作られたスレッド(cloneプロセス)では、 pthreadライブラリの中で上手に解決しているらしく、 defunctはできませんでしたので、こちらを使うほうがお手軽のようです。 もう、ここまできたらついでなので、サンプルを紹介します。 -- clone --- #include <sched.h> #include <signal.h> char stk[4096]; main() { int xx(); int arg[1]; signal(SIGCHLD, SIG_IGN); arg[0] = 555; __clone(xx, stk+4096, CLONE_VM|CLONE_SIGHAND, (void *)arg); while (1); } int xx(void *arg) { int x; x = (int)((int *)arg)[0]; printf("x=%d\n", x); } -- clone --- 単にccして、実行できます。 親側はwhileで止まっていますので、ps -ef で見ると defunctが残っているのがわかります -- pthread -- #include <pthread.h> int main() { void *xx(); pthread_t pth; int arg[1]; arg[0]=555; pthread_create(&pth, NULL, xx, (void*)arg); while (1); } void* xx(void *arg) { int x; x = (int)((int *)arg)[0]; printf("x=%d\n", x); } -- pthread -- ccするときに、-lpthread を指定してください。 同じように親は止まっていますが、今度はゾンビが ないのがわかると思います。 -- shmget/shmat メモリ提供側 -- #include <stdio.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #define DSIZE 1000000 int main(int argc, char **argv) { key_t key = 123; int shmid; int *p; int i; if (argc > 1) key = atoi(argv[1]); if ((shmid = shmget(key, sizeof(int)*DSIZE, IPC_CREAT|SHM_R|SHM_W)) == -1) { fprintf(stderr, "Can't get shmid\n"); exit(1); } printf("shmid=%d\n", shmid); if ((p = (int*) shmat(shmid, 0, SHM_RND)) == (int*)-1) { fprintf(stderr, "Can't attach shmid\n"); exit(1); } printf("p=%08x\n", p); for (i = 0; i < 100; i++) { *p = i; p++; } while (1); return 0; } -- shmget/shmat メモリ提供側 -- -- shmget/shmat メモリ共有側 -- #include <stdio.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #define DSIZE 1000000 int main(int argc, char **argv) { key_t key = 123; int shmid; int *p; int i; if (argc > 1) key = atoi(argv[1]); if ((shmid = shmget(key, sizeof(int)*DSIZE, SHM_R)) == -1) { fprintf(stderr, "Can't get shmid\n"); exit(1); } printf("shmid=%d\n", shmid); if ((p = (int*) shmat(shmid, 0, SHM_RND)) == (int*)-1) { fprintf(stderr, "Can't attach shmid\n"); exit(1); } printf("p=%08x\n", p); for (i = 0; i < 100; i++) { printf("%d\n", *p); p++; } shmdt(p); return 0; } -- shmget/shmat メモリ共有側 -- 単にccで実行できます。 端末を2つ開いて、提供側を実行しておいてから、 共有側を実行すると、値が共有されているのが わかると思います。 数千のプロセスですか、ネットワーク対戦ゲームでも 作成されるのでしょうか? 楽しみですね。 ところで、数千のプロセスはたぶんシステムのプロセス数上限に あたり実行できないと思います。 上限設定を変えて実行できたとしても、Linuxはプロセススケジューラが ガタガタなので、まともに動作しないでしょう。 工夫が必要です。

zukka
質問者

お礼

これまでの質問に対する回答大変ありがとうございました。 とても的確で分かりやすい回答でした。 また、何か分からないことがあったら、質問に答えてください。 cloneでゾンビプロセスを回避する方法が分かりました。 __clone(xx, stk+4096, CLONE_VM|CLONE_SIGHAND, (void *)arg); を __clone(xx, stk+4096, CLONE_VM|CLONE_SIGHAND|SIGCHLD, (void *)arg); にすると、クローンのプロセスが終了した時にSIGCHLDシグナルが親プロセスに送信されゾンビプロセスが出来ませんでした。

その他の回答 (2)

  • kaz-sugi
  • ベストアンサー率50% (3/6)
回答No.2

Linuxの話で良いようですね。。。 お近くにLinuxが使えるPCがあれば、その端末で 「man clone」にてcloneシステムコールの使い方などが ごらんになれると思います。 それによると、残念ながらcloneで並列化できるのは、 関数のみで、実行ファイルは呼び出せません。 cloneのあとにexecシステムコールを呼び出すことで、 実行ファイルは呼び出せるでしょうが、もはやメモリの 共有はなくなります。 cloneやpthread_createにて作られるメモリの共有関係ではない 共有メモリをご使用になりたいのであれば、shmやmmapを 使うしかないと思います。 単にプロセス間通信をしたいのであれば、pipeや、socketという 手もあります。 何をされたいのかよくわかりませんが、別の実行ファイルを 呼び出した上で、それとの間で共有メモリ、、ということであれば、 スレッドの話は関係ないかと思います。 どうしてshmを使いたくないのかわかりませんが、、、 もしかして面倒なのですか? shmgetや、mmapをmanでごらんになってみてください。 UNIXやLinuxでのプログラミングを解説している本を1冊 読んでみるのも良いかと思います。 cloneで作ったプロセス間で、pthread_mutex_lock等が有効に 機能するかどうかは知りません。。。 動くかもしれませんね。 ちなみに、おせっかいですが、題になっている「スレッドとは?」 cloneやpthread_createで作られるスレッド (Linuxではライトウェイトプロセスと言ったほうが良いのかも しれませんが)とは、CPUの割り当てられる実行の単位です。 Machオペレーティングシステムでは、スレッドと対になる 概念としてタスクがあり、タスクとはメモリ空間や、 ファイルディスクリプタなどのプログラムの実行の環境のことを 差します。 スレッドがタスクという資源を使って動作することにより、 CPUがメモリやファイルを参照しながら動作する、、というのと近い イメージになります。 普通のUNIXでいうプロセスは、1タスクにつき1スレッドが対応している ことになります。 「マルチスレッド」とは、1つのタスクの中に複数の スレッドがある状態を指し、おのおののスレッドは、 タスクを共有するため、メモリを共有していることになります。 普通、マルチプロセスではなくマルチスレッドを使うのは、 プロセスよりも小さい単位で、処理を並列化したい場合に使用します。 これは、マルチCPUのコンピュータで大きな効果をあげるために よく利用されます。 例えば、forループで10000回繰り返すような演算で、 1回ごとの処理は最終結果を出すところまで関連しない、、 なんて場合に、CPUが2個とか4個とかあれば、それぞれ5000回ずつとか、 2500回ずつ受け持つことで処理時間を短くできます。 普通、プロセスの切り替えよりもスレッドの切り替えのほうが オーバーヘッドが小さいというのも、理由のひとつです。 Linuxのpthread_createは、その延長で結局はcloneシステムコールが 呼び出されます。 実は別のプロセスが作られていて(psコマンドでもそれは 確認できます)、1タスクに複数スレッド、、というイメージをは 違いますが、メモリを共有させることで、マルチスレッドと 同じような処理を行うことができるわけです。。。 さらに蛇足ですが、普通のUNIXではプロセスの生成には forkシステムコールを使います。Linuxにもあります。 fork後の呼び出し元プロセスと生成されたプロセスの メモリは参照においてのみ共有されています。。 ですが、お互いのメモリの書き換えは、相手には伝わりません。 cloneで作ったプロセス間ではそれが伝わる、という言い方もできるかも しれません。

zukka
質問者

お礼

分かりやすい説明ありがとうございます。 度々申し訳ありませんが、質問よろしいでしょうか。 今考えているシステムでは、プロセスの数が数千以上が同時に存在する場合があり、各プロセスに対して共有のメモリをshmXXで使用すると、必要なメモリが大量になる為にスレッドでのメモリの共有を考えています。 各プロセスに対して共有のメモリをshmXXで使用した場合、プロセス数*共有メモリのサイズ必要になると思うのですが、間違いはないでしょうか? cloneで生成されたプロセスが、終了した時のゾンビプロセスの回避方法はどうすればよいのでしょうか?

  • kaz-sugi
  • ベストアンサー率50% (3/6)
回答No.1

質問のタイトルからすると、マルチスレッドしたいのでしょうか・・・。 Linuxと仮定しますと、、 (下記のソースは概要であり、このまま動作しません) #include <pthread.h> #define NTHREADS 10 /* 適当 */ #define NARGS 5 /* 適当 */ pthread_t thread[NTHREADS]; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int data = 5; /* 適当 */ xxx() { int i; int arg[NARGS]; int yyy(); for (i = 0; i < NTHREADS; i++) { arg[0] = i; /* 適当 */ pthread_create(&thread[i], NULL, yyy, (void*)arg); } } yyy(void *arg) { int x; x = ((int *)arg)[0]; pthread_mutex_lock(&mutex); data++; pthread_mutex_unlock(&mutex); printf("%d) %d\n", x, data); } Linuxでは、スレッドの変わりにクローンプロセスというのができあがり、 見かけ上は、プロセス内に複数のスレッドができたのと同じように振舞わせるように、 pthreadライブラリがあり、それを上記のように使うと楽です。 スレッド(クローンプロセス)間では、スタック(ローカル変数)以外の、 データ(グローバル変数)は、共有されています。 (cloneシステムコールを使うと、もっと詳細に共有部分を設定できます) 共有しているデータへのアクセスの際に、 スレッド(クローンプロセス)間での同期をとるために、 pthread_mutex_lock/unlock を使用します。 上の例では、関数yyy()がマルチスレッド(クローンプロセス)により 実行されます。 ちなみに、 親子関係でないプロセス間で、本当の意味で共有メモリをするのであれば、 shmget/mat以外には、mmapというシステムコールがあります。

zukka
質問者

お礼

ありがとうございました。大変参考になりました。 もう一つ質問ですが、cloneの使い方で呼ぶ関数は、内部関数のみなのですか? 実行ファイル等呼べるのであれば、使い方を教えて下さい。 cloneを使った場合にもpthread_mutex_lock等は使用可能ですか?

関連するQ&A

  • windowsでのプログラミングについてなんですけど。

    UNIXの本を読んでると、プログラムはexitシステムコールが呼ばれると、 freeregを呼び出し、malloc済みメモリをすべて開放し、共有メモリについても 参照が0になったら解放するようになっていて、仮にメモリリークする プログラムで会ってもプロセスを殺せば、そのプログラムのリークした分は すべて解放されるんですよ~~~それと同じ感覚で、windowsでプログラム やってる友達に聞いたら、プロセスを殺してもnewでリークしたのしっぱなしに なるっぽいよ~って言ってたんですよ。それって本当なんですか? てか本当ならあえてそうしてるメリットってあるんでしょうか?

  • スレッドの意味

    マルチスレッドについて良い資料が見当たらず、教えて下さい。 OSにおけるマルチスレッドと言うと、同一プロセス内でメモリ空間を 共有して独立に動く一連の手続き、と捉えています。(シングルCPU シングルコアだとOSで時分割によって作られた仮想的な並列計算) Javaのようなマルチスレッドのプログラミング言語では「一つの プログラムから作られた二つの一連の手続き」と言うイメージが あります。※裏側の動作ではOSに依頼してJavaのプロセス内で OSのスレッドを生成して処理を渡しているだけ?と思っています。 CPUコアの内部で説明される「マルチスレッド」と言うのは、 どのようなレベルのスレッド(何が並列処理?何処まで並列?) なのでしょうか。

  • Linuxでのスレッド間メッセージについて

    Linuxでスレッドを複数生成し、スレッド間でメッセージのやり取りをしたいと思っています。 ネットで色々検索したのですが、欲しい情報にめぐり合えていません。 # WindowsのPostThreadMessage()みたいなものを探しています。 #「プロセス間通信」というものは発見しましたが・・・ 何か方法はありますでしょうか? スレッド間のメッセージのやり取りの方法がない場合は代替案も教えて頂きたいです。 # セマフォを用いて共有メモリアクセスかな?と思っています。

  • パフォーマンスモニタのメモリについて

    1.パフォーマンスモニタであるPrivate Bytes、Working Setがいまいち理解できませんが、下記の認識であっておりますでしょうか。 (1) 仮想メモリ 物理メモリが不足したときに使用するハードディスク上に設定した仮想メモリ(ページングファイル) (2) Private Bytes : ほかのプロセスから共有されない仮想メモリサイズ (3) Working Set : プロセスが使用している物理メモリサイズ 2.認識があっている場合、Working Setは、他のプロセスと共有されていますでしょうか。 Working Setがほかのプロセス共有されていないとのことでしたら、Private Bytesと Working Setを足した値がそのプロセスが使用しているメモリの合計ということでしょうか。

  • 二重起動チェックについて

    Solarisで、プロセスの二重起動チェックを行いたい のですが、システムコールの使用など簡単に行える 方法はないでしょうか? よろしくお願い致します。

  • 実行中のプロセスのシステムコールフックについて

    表題の通り,実行中のプロセスのシステムコールのフックについて質問があります. 現在,Linux上の全てのプロセスがどんなシステムコールを使って,どんなリソースにアクセスをしているのか調査しているのですが 具体的には以下のURLのソフトと同じものを,Linux上でC言語を用いて作りたいと考えています. [Process Monitor] http://www.microsoft.com/technet/sysinternals/utilities/processmonitor.mspx いろいろ調べていく中で strace http://www.netadmintools.com/html/1strace.man.html を使うと目的としている調査が実装できそうだということでさっそくいじってみたのですが, strace では既に実行されているプロセスのシステムコールの呼び出しをトレースすることはできないようでした. そこで1点質問なのですが,既に実行中のプロセスのシステムコールをフックするにはどのような方法を使えばいいのでしょうか. お分かりになるかたご回答よろしくお願いします. こちらの開発環境は以下です. OS: Debian 4.0 Kernel: 2.6.20-16 gcc: 4.1.2 (3つとも11/9現在の最新版を使用しています)

  • 共有メモリの同時アクセスについて教えてください。

    2つのプロセスが同時に同じ共有メモリにアクセスすることは可能ですか? ミューテックスや、セマフォなどの排他制御を外せばできたりしませんか? 片方のプロセスで共有メモリから、データの一部をHDDに保存しつつ、それと同時に、もう片方のプロセスで共有メモリからデータの中身を表示させたいのですが・・・。

  • CPU使用率が100%になってしまいます

    ファンの稼動が激しいため、タスクマネージャをみたところ、CPU使用率が100%のまま変わりません。プロセスのiexpore.exeが90~99でメモリ使用量が36104Kになっています。普段は、たしか、System Idle Processが90~99なはずなのですが、このようにCPU使用率が100%の時は、System Idle ProcessのCPUが0で、メモリ使用量は、16Kになってます。CPU使用率を下げる方法はありますでしょうか?

  • 32ビットCPUのメモリについて

    32ビットCPUの場合、アドレス空間の制限で1プロセスにつき4GBまでしか使用できないことになっていると思いますが、このうち2GBはシステム用、その他2GBがアプリケーション用と聞いたことがあります。1プロセスで使用する度にOSに2GBほどのメモリを使用することがあるのでしょうか?(プロセスが多くなる度にOSで使用されるメモリ量も増大すると考えてよろしいでしょうか?)

  • Windowsのメモリ使用量が稼働プロセスと不一致

    Windows で使用しているメモリ量をプロセスごとに把握する際に、 検算としてリソースモニタのメモリタブに表示されるプロセスのメモリ量を合計してみましたが、 その容量がリソースモニタで表示されている物理メモリの使用サイズと一致しません。 ■使用マシン  OS : Windows Server 2008 R2 Enterprise 64bit  物理メモリ容量 : 16 GB ■リソースモニタでの出力内容  物理メモリ使用量 : 11241 MB  リソースモニタに表示されるプロセスの全メモリ合計(ワーキングセット) : 8306 MB  リソースモニタに表示されるプロセスの全メモリ合計(コミット) : 9509 MB タスクマネージャや tasklist コマンドで表示されるプロセスのメモリを合計しても、 同様に「物理メモリ使用量」の値に届かないため、プロセス外の何らかのものが メモリを使用していると推測されますが、実際はどうなのでしょうか? (共有メモリなど特定のプロセスに属さないメモリ領域など??) また、そういうものがあった場合、そのメモリ使用量をどのように確認すればよいでしょうか?

専門家に質問してみよう