お茶漬けぶろぐ

マルチプロセスとマルチスレッドの区別

C++でマルチスレッドにプログラムを書いた事はあったので、並列動作の基本はOKだぜ!と思っていた。

ネットで拾ったコードを特に意識せずいじっていたらどうしてもうまくいかなくて、途中で気づいた。これマルチスレッドじゃなくてマルチプロセスだ。

というわけで区別しましょう。

まずはマルチプロセス

まずはマルチプロセス。fork()関数で子プロセスを作るんだけど、これ、状態を全部コピーした上で子プロセスが動く。例えば以下のようなコード。

[cpp]
#include #include using namespace std; int i;

int main(){
i=0;
cout«“process fork test”«endl;
pid_t pid;
if((pid = fork()) == 0){
cout«“this is child”«endl;
sleep(10);
cout«“child dead”«endl;
cout«“i:”«i«endl;
}else{
sleep(5);
cout«“this is parent”«endl;
i++;
}
return 0;
}
[/cpp]

fork()は、プロセスをフォークしてくれる関数だが、この戻り値をうまく使う。戻り値は、当人が(?)子プロセスの場合には0、親プロセスの場合には子プロセスのPIDを与える。

これを実行すると、

[tea@teaarch]$ ./a.out process fork test this is child this is parent [tea@teaarch]$ child dead i:0

のようになる。

実行の順番は、

  1. i=0に初期化
  2. フォーク
  3. 5秒経過
  4. 親プロセスが自己紹介してi++;して終了
  5. 5秒経過
  6. 子プロセスが自己紹介してiの中身を出力して終了

単純に考えると、6.では1を出力しそうなもんだが、別プロセスであり、(マルチスレッドの時のように)共有していないので、インクリメントされる前のiを子プロセスは持っており、インクリメントされないまま出力を迎える。

それから、親プロセスが終了した時点で、制御が帰ってくるみたい。(親プロセスが終了しても子プロセスは生き残る)

それからマルチスレッド

こちらはプロセスの中で処理スレッドを増やすものなので、メモリ空間は共有。例えば以下みたいなコード。

[cpp]
#include #include #include using namespace std;

int i;

void sub_thread(){
cout«“[s]this is sub thread”«endl;
sleep(3);
cout«“[s]i:”«i«endl;
sleep(3);
cout«“[s]i:”«i«endl;
}

int main(){
i=0;
cout«“multi thread test”«endl;
thread t(sub_thread);
t.detach();
cout«“[m]sleep…”«endl;
sleep(5);
cout«“[m]increment”«endl;
i++;
cout«“[m]sleep…”«endl;
sleep(5);
return 0;
}
[/cpp]

コンパイル時には忘れずライブラリくっつけておく。g++ ./thread.cpp -lpthreadみたいな感じ。実行すると、

[tea@teaarch]$ ./a.out multi thread test [m]sleep... [s]this is sub thread [s]i:0 [m]increment [m]sleep... [s]i:1

動作は、

  1. i=0に初期化
  2. サブのスレッドt作成(中身はsubthread()が動作する)
  3. detach()でスレッドtの管理を放棄(スレッドtが終了するまで待つのは.join())
  4. 3秒経過
  5. サブスレッドがiの中身表示(0)
  6. 2秒経過
  7. メインスレッドがiをインクリメント
  8. 1秒経過
  9. サブスレッドがiの中身表示(1)
  10. 4秒経過
  11. メインスレッドが最後のスリープをして終了

これ、最後のスリープをしないと、メインスレッドが5秒経過後インクリメントした直後にプロセスが終了する。サブスレッドは6秒たたないと2回めの表示をしないので、つまり、1回目の表示しか実行されない。

まとめ

マルチプロセス:fork()とかでうまくやる。メモリの状況はコピーされ、共有されない。親プロセスが終了しても子プロセスは生き残る。親子プロセスで何かやりとりしたければプロセス間通信の手を考える必要がある?(名前付きパイプとか?)

マルチスレッド:threadでうまくやる。メモリの状況は共有される。メインスレッドが終了すると派生した方のスレッドも終了する。スレッド間のやり取り自体は難しくないが、タイミングの制御やロックなど考えないと死ぬ(よくあるマルチスレッドの注意点)

< bashでゼロパディングする手法2つ

PDFを結合する(pdftk) >