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

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

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

 

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

 

まずはマルチプロセス

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

#include <iostream>
#include <unistd.h>
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;
}

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を子プロセスは持っており、インクリメントされないまま出力を迎える。

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

 

それからマルチスレッド

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

#include <iostream>
#include <thread>
#include <unistd.h>
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;
}

コンパイル時には忘れずライブラリくっつけておく。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でうまくやる。メモリの状況は共有される。メインスレッドが終了すると派生した方のスレッドも終了する。スレッド間のやり取り自体は難しくないが、タイミングの制御やロックなど考えないと死ぬ(よくあるマルチスレッドの注意点)

PDFを結合する(pdftk)

PDF結合?取り敢えずImageMagickやろwwwwwwとか思ってconvertバシバシ叩いてたんだけど、圧倒的メモリ不足で全然終わらない(RAM4GB+Swap4GBを全部食い潰していた)

なんやこれと思って暫く悩んでいたんだけど、どうしようもないのでぐぐってみたら、一発目から「pdftk使っとけよw」って煽られたのでそういうことだ。(´・ω・`)

 

pdftk、分割しか出来ないと勝手に思い込んでいた

pdftk [INPUT FILES] cat output [OUTPUT FILE]

処理もサクッと終わるとメモリも全然食わない

わからなければ素直にぐぐりましょう。

Windows10で複数枚モニタの壁紙を設定する

Windows+Iの設定で普通に設定する事は出来るが、やりにくい。

背景設定で、選択したい画像を右クリックすると、どのモニターに設定するか訪ねてくれる。

しかし、この画面ではサムネイルしか見れず、またファイル名も見れない。特にwaifu2xなどで拡大した場合など、非常にわかりにくい。

また、参照ボタンから画像を追加出来るが5つまでしか履歴が保持されない。フォルダ内に壁紙ファイルを放り込んでおき、一覧されたサムネイルから選択する事が出来ない。画像が多い場合には不便だ。

Windows10の設定アプリは諦めようかと思ってもダメ。

コントロールパネルを利用しようとすると、デスクトップのカスタマイズ→個人設定で背景設定へ移動してもWindows10の設定アプリが湧いてきて無意味だ。

しかし、コントロールパネルの中に壁紙を設定するUIや機能はそのまま残っているらしく、直接呼び出せばいけるらしい。

Windows 10のデュアルモニターで別々の壁紙を使いたい – 世の中は不思議なことだらけ

コントロールパネルをそれらしい引数で起動する。

control /name Microsoft.Personalization /page pageWallpaper

上記参考サイトではexplorerのロケーションとして上記を指定するようだが他にも、

・Windows+R(ファイル名を指定して実行)から実行する

・cmd内で実行する

・ショートカットのリンク先として指定する

などでも使える。てきとうなところにショートカットとして用意しておくのが便利で良い。