C++でマルチスレッドにプログラムを書いた事はあったので、並列動作の基本はOKだぜ!と思っていた。
ネットで拾ったコードを特に意識せずいじっていたらどうしてもうまくいかなくて、途中で気づいた。これマルチスレッドじゃなくてマルチプロセスだ。
というわけで区別しましょう。
まずはマルチプロセス。fork()関数で子プロセスを作るんだけど、これ、状態を全部コピーした上で子プロセスが動く。例えば以下のようなコード。
[cpp]
#include
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
のようになる。
実行の順番は、
単純に考えると、6.では1を出力しそうなもんだが、別プロセスであり、(マルチスレッドの時のように)共有していないので、インクリメントされる前のiを子プロセスは持っており、インクリメントされないまま出力を迎える。
それから、親プロセスが終了した時点で、制御が帰ってくるみたい。(親プロセスが終了しても子プロセスは生き残る)
こちらはプロセスの中で処理スレッドを増やすものなので、メモリ空間は共有。例えば以下みたいなコード。
[cpp]
#include
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
動作は、
これ、最後のスリープをしないと、メインスレッドが5秒経過後インクリメントした直後にプロセスが終了する。サブスレッドは6秒たたないと2回めの表示をしないので、つまり、1回目の表示しか実行されない。
マルチプロセス:fork()とかでうまくやる。メモリの状況はコピーされ、共有されない。親プロセスが終了しても子プロセスは生き残る。親子プロセスで何かやりとりしたければプロセス間通信の手を考える必要がある?(名前付きパイプとか?)
マルチスレッド:threadでうまくやる。メモリの状況は共有される。メインスレッドが終了すると派生した方のスレッドも終了する。スレッド間のやり取り自体は難しくないが、タイミングの制御やロックなど考えないと死ぬ(よくあるマルチスレッドの注意点)