- ベストアンサー
flockの使用による子プロセスの終了とロックの問題
- flockを使用して親プロセスから子プロセスを複数呼び出し、子プロセスが終了した後に次の手順に移行する処理を作成しているが、うまく動作しない。
- main.plを実行すると、lock.plを10回呼び出して、すべて終了したら「OK」と表示したいが、子プロセスが終了していないのに「OK」の表示が出力される。
- flockは順番を守らずロックを解除するため、正しく動作しない可能性がある。問題解決のためには、別の方法を検討する必要がある。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
質問の趣旨に合っているかわかりませんが、プログラムを作ってみました。ロックした後の処理に時間がかからなければ、順番どおりに実行されると思います。 main.pl -------------------------- #!/usr/bin/perl foreach (1 .. 10) { system("./lock.pl $_ &"); } lock.pl -------------------------- #!/usr/bin/perl use Fcntl ':flock'; use POSIX ':sys_wait_h'; $arg = $ARGV[0]; sleep $arg; $pid = fork(); die "Can't fork: $!" unless defind $pid; if ($pid) { do { $kid = waitpid(-1, &WNOHANG); } until $kid == -1; if ($arg == 10) { print "MAIN LOCK\n"; open LC, "+<lock" or die; flock LC, LOCK_EX or die; print "OK\n"; } } else { print "lock $arg\n"; open LC, "+<lock" or die; flock LC, LOCK_EX or die; print "release $arg\n"; }
その他の回答 (3)
- kumoz
- ベストアンサー率64% (120/185)
No1 です。 > system("./lock.pl $_ &"); 上記のように書いた場合は、制御が非常に難しいと思います。& がなければ親プロセス (PPID) は main.pl になりますが、& を付けた場合は main.pl が親プロセスにならず切り離されてしまうからです (私が使っている Linux の場合)。
お礼
> 上記のように書いた場合は、制御が非常に難しいと思います。 そのようですね。 実はこのやり方はsolarisで試行錯誤をしてうまく行ったやり方だったのですが、 Linuxであっさりうまくいかなくなり、ご質問させていただきました。 (cygwinでもダメでした・・・) 今あらためて、solarisだと動きは素直でした。。。
- osamuy
- ベストアンサー率42% (1231/2878)
プロセスがどのようなタイミングで動くはOSのスケジューラ次第です。 親プロセスのCPUタイムに余裕があるなら、forループに続けて、ロックの獲得・解放まで処理が進みます。 なので、 >子の全部の処理が終わった時点で、mailにロックが移る。。。 と思ったのが敗因かと。 子プロセスとの同期には、waitpidやsigchildなど別の仕掛けがありますので、そちらを使ってみては。
補足
forループのあとに5秒おいて、必ず子が先に始まるようにしているのですが、 ダメなんですよね・・・ なので、仰っていることの半分くらいはわかるのですが、 >forループに続けて、ロックの獲得・解放まで処理が進みます。 はprint文を入れてログを出してみてもちゃんと最後に(1)が実行されているのですが・・・ >waitpidやsigchildなど別の仕掛け そうなんですね。調べてみます。 ありがとうございました。
- kumoz
- ベストアンサー率64% (120/185)
> system("./lock.pl $_ &"); ↓ system("./lock.pl $_"); 通常は system 関数が終わるまで待ちますが、バックグラウンドで子プロセスを起動しているため終了を待たないためと思います。& を消せば、すべての sleep がなくても順番どおりに実行されるはずです。
お礼
回答ありがとうございました。 説明不足で申し訳ありません。 多重で実行したいので&をつけております。
お礼
おお! サンプルありがとうございます! とりあえず、なるべく現行を変えないでということで、 子スクリプトで実行時にフラグファイルを作るようにして、 そのフラグを親スクリプトが発見するまで待つようにしてみました。 for ( 0 .. 19 ){ system("[子スクリプト] $_ &"); # ←この引数$_を子スクリプトでフラグとして作成 for( 0 .. 600 ){ if( -f $_ ){ last; } sleep 1; } } こんな感じにしたら、親のロックが最後になるようになったため 大丈夫になりました! ループを600にしてるのは、600秒も開始しない場合はなにかおかしいだろうということで ここには書きませんでしたが、exit 1 するようにしました。 ※ しかしながら、この子供って結構重い処理なのですが、6分ぐらい開始しない、ということがありました。 sparcのsolarisではそんなことなかったので、ちょっと驚きました。