• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:remove関数(?)でプロセスが停止する。)

remove関数でプロセスが停止する原因と回避方法

このQ&Aのポイント
  • remove関数とmkdir関数が同時に実行すると、プロセスが停止してしまう現象が発生します。
  • この現象の原因は、両方の関数が同じディレクトリを操作しようとすることで発生します。
  • 回避する方法としては、両方の関数を順番に実行するか、排他制御を行うことが挙げられます。

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

  • ベストアンサー
  • hidebun
  • ベストアンサー率50% (92/181)
回答No.13

これ以上は、私も原因の推測がつきません。 ディレクトリやファイルを高い頻度で作成・削除するシチュエーションには、 問題があると思うので、ディレクトリを起動時に一度だけ作るようにできないか 検討したり、mutexやsemaphoreを使ったり、キューを使ったりして、対象ファイルと ディレクトリへのアクセスを制御する、対症療法ぐらいしか思いつきません。 調査可能な期間との兼ね合いになりますが、私なら、この辺りまで調べたら、 構造的な部分の問題を解消する方に、注力します。

sav_moster
質問者

お礼

色々とご指導いただき、ありがとうございました。 根本的原因は解決できませんでしたが、おっしゃられるように、 >調査可能な期間との兼ね合いになりますが、私なら、この辺りまで調べたら、 >構造的な部分の問題を解消する方に、注力します。 の方向で検討することにしたいと思います。 誠にありがとうございました。 大変勉強になりました。 以上、よろしくお願いいたします。

その他の回答 (12)

  • hidebun
  • ベストアンサー率50% (92/181)
回答No.12

http://wiki.livedoor.jp/linuxfs/d/2.6.21-rc1_shortlog11 で、2.6.21でFIXされたと思います。

sav_moster
質問者

補足

ご回答、ありがとうございます。 カーネルのバージョン自体は問題なさそうでした。 その他、思い当たる節はありますでしょうか? 途方にくれています。

  • hidebun
  • ベストアンサー率50% (92/181)
回答No.11

使用しているLinuxの種類、Kernelのバージョンはいくらでしょうか? removeを呼び出した時に、ファイル削除関数 unlinkが呼ばれるようですが、 そのunlinkのロック機構に不具合があるようなことが書いてあるように思います。 http://lkml.indiana.edu/hypermail/linux/kernel/0702.0/1304.html これが原因だとすると、Kernelをバージョンアップするか、 mkdirとremoveがこれほど高頻度にバッティングしないように、プログラムの制御構造を変えるしかないように思います。 といっても、確率が低くなるだけで、他のプロセスとバッティングしてしまえば、不具合は発生しますが。

sav_moster
質問者

補足

ご回答ありがとうございます。 すみません。上記のunlinkのBUGなんですが、 linuxのカーネルバージョンがいつく以下だと発生するのでしょうか? ちょっと英語も翻訳して確認してみたのですが、 わかりませんでした。 ご存知でしたら、教えてください。 以上、よろしくお願いいたします。

回答No.10

>ここでkillしても、状況は改善せず、/varディレクトリのファイルシステムが壊れているしまっているようです。 killしてもスレッドAがファイルをつかまえているのですよね? ということは、ファイルシステムの問題とは確定できないと思います。 kill -SIGKILL {pid} でも殺せないのでしょうか? これで殺せて、fuserも解放されて、 ls /varが見えるようになったのなら、プログラムの問題で 改善しないなら、ファイルシステムの問題が疑えると思います。 ファイルシステムっぽいのなら、 /varということはUNIXやLinuxでしょうから、シングルユーザーモードでブートし直して(/varをマウントしてない状態で) ファイルシステムのチェック(e2fsckとかfsckとかOSに合わせて)を行ってみてはどうでしょう。

sav_moster
質問者

補足

ご回答ありがとうございます。 >kill -SIGKILL {pid} でも殺せないのでしょうか? >これで殺せて、fuserも解放されて、 ls /varが見えるようになったのなら、プログラムの問題で >改善しないなら、ファイルシステムの問題が疑えると思います。 kill -9 {pid}だと殺せました。 ここで、fuserは解放されましたが、 ls /var は見えないままです。 ファイルシステムでしょうか? ただし、再起動すると ls /varでアクセスできるようになります。

  • hidebun
  • ベストアンサー率50% (92/181)
回答No.9

プロセスとスレッドが混在して使われていますが、 今回は、プロセスAとプロセスBの方が、状況を説明する用語としては適切ではないでしょうか。 ファイル作成プロセスと、ディレクトリ削除プロセスは、別のプロセスなわけですから。 さて、本題に戻りまして、/var/tmp/test.dat は、プロセスAがリソースを握っていたんですね。 一方、 > /varディレクトリにすらアクセスできなくなってしまいます とありましたが、このディレクトリ(/var)については、 fuserで、調査されたでしょうか? また、プロセスA(ファイルを握っているプロセス)をkillしたとのことですが、 killできない状況とのこと。では、killの強制削除オプション(-9)で、 そのプロセスを削除してみると、/varへのアクセスは回復するでしょうか? kill -9 pid

sav_moster
質問者

お礼

すみません。追加です。 linuxを再起動すると、/varにはアクセスできるようになります。 (直っている?)

sav_moster
質問者

補足

>今回は、プロセスAとプロセスBの方が、状況を説明する用語としては適切ではないでしょうか。 >ファイル作成プロセスと、ディレクトリ削除プロセスは、別のプロセスなわけですから。 おっしゃるとおりです。 了解しました。 先ほどの説明に少し御幣があった+自分自身でも調査不足だったので、 改めて説明させてください。 プロセスAとプロセスBを同時に実行した際に、 remove関数とmkdir関数がぶつかると停止するようです。 ログを確認すると、 remove start mkdir start と出力され、ストップしています。 /var/tmp/test.datをremoveしている際に、 /var/tmp/etc/test1をmkdirすると発生しているようです。 で、発生した時点でのプロセスはA、Bとも生きていました。 ここで、fuserを使って調べると、@ /var プロセスAが握っている /var/tmp/ プロセスAが握っている /var/tmp/test.dat そんなファイルはないといわれる。removeは途中で終わっているが、ファイルは消えているようです。 /var/tmp/etc/ プロセスAが握っている となっていました。 ここで、kill -9 プロセスAとしたところ /var なし /var/tmp/ なし /var/tmp/test.dat そんなファイルはないといわれる。 /var/tmp/etc/ なし となりました。 ただし、cd /varで移動するとkillする前と同じく、 移動して、lsしてもなんの反応もなく、 いったん移動してしまうとどんなコマンドも効きませんでした。 (ファイルシステムが壊れている??) 以上、よろしくお願いいたします。

  • hidebun
  • ベストアンサー率50% (92/181)
回答No.8

BIOSに不具合がある可能性もあることを指摘しましたが、 BIOSをUpdateしましたか? 次に、あなたが生成したプロセスは、終了するのですか?しないのですか? プロセスが終了していないなら、プロセスをkillして、状況が改善するか確認しましたか? プロセスが終了していて、なおかつ、その状態が継続するなら、 fuserコマンドで、特定のリソース(ディレクトリ・ファイル)を誰が使用しているか、 調べてみてはいかがでしょうか? http://www.itmedia.co.jp/enterprise/articles/0711/20/news047.html 最後に、私が「擬似コードではなく、テストコードをそのまま載せた方が良い」 と、アドバイスを送りましたが、fcloseの下りもそうですが、printfも、 このコードでは、コンパイルが通らないでしょう?ダブルクォートが原因で。 printf("fclose (%d")\n", ret); ・無用なやり取りを防ぐため ・親切な人が状況を再現するために、コンパイルできる最小コードの提示 ・本人が問題ないと思って端折った箇所に、不具合は潜んでいることが多い などの理由から、そのようにアドバイスを送りました。 おわかりいただけますでしょうか?

sav_moster
質問者

補足

ご回答ありがとうございます。 >BIOSに不具合がある可能性もあることを指摘しましたが、 >BIOSをUpdateしましたか? すみません。BIOSのアップデートはしていませんでした。 確認したところ、BIOSは最新です。 >次に、あなたが生成したプロセスは、終了するのですか?しないのですか? >プロセスが終了していないなら、プロセスをkillして、状況が改善するか確認しましたか? プロセスは終了せずに固まったままです。 ここでkillしても、状況は改善せず、/varディレクトリのファイルシステムが 壊れているしまっているようです。 >fuserコマンドで、特定のリソース(ディレクトリ・ファイル)を誰が使用しているか、 >調べてみてはいかがでしょうか? 調べたところ、スレッドAのプロセスがまだ握っている状態でした。 (killしているのですが。。。) >printf("fclose (%d")\n", ret); >・無用なやり取りを防ぐため >・親切な人が状況を再現するために、コンパイルできる最小コードの提示 >・本人が問題ないと思って端折った箇所に、不具合は潜んでいることが多い >などの理由から、そのようにアドバイスを送りました。 申し訳ございませんでした。 コンパイルできる最小コードを見直しました。 もう一度、すべてを記載しなおします。 ■スレッドA int a = 0; int ret = 0; for(a = 0; a < 1000; a++){ fp = fopen("/var/tmp/test.dat", "wb"); if (fp == NULL) { return ; } ret = fclose(fp); printf("fclose (%d)\n", ret); if( ret != 0) { return; } printf("remove start\n"); ret = remove("/var/tmp/test.dat"); printf("remove end (%d)\n", ret); } ■スレッドB int a = 0; int ret = 0; for(a = 0; a < 1000; a++){ rmdir("/var/tmp/etc/test1"); printf("mkdir start\n"); ret = mkdir("/var/tmp/etc/test1"); printf("mkdir end (%d)\n", ret); } 以上を踏まえて、もう一度ご確認いただけないでしょうか? 以上、よろしくお願いいたします。

回答No.7

本当にそのコードで、「remove star」が表示されたのなら、(最後のtは表示されないんですか?)「fclose」が表示されないのはおかしいと思いませんか? 思っているよりも前の段階で、制御を失っている可能性がありますね。

sav_moster
質問者

補足

すみません。 わかりやすくどこの止まっているかを伝えたかったので、 fcloseははしょってました。 もちろん、fcloseも出力されています。 あと、"t"がないのは、タイポです。 remove start と表示されています。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.6

「処理がとまった」ときに, そのままほかっておいたら戻ってきたりしませんか?

sav_moster
質問者

補足

2時間ほど放置しても戻ってこないのです。

回答No.5

fclose("/var/tmp/test.dat"); でじゃなくて、fclose(fp);じゃないですか? もしかして、fpが解放されてないまま、同時ファイルオープン数がOSの限界近くまでいって、 別プロセス実行でたまたま限界を超えてしまう。ってことはありませんか?

sav_moster
質問者

補足

すみません。 fclose(fp); です。コピーするときに間違えました(汗 すみません。なので、fcloseは正しく動いていると思います。

  • hidebun
  • ベストアンサー率50% (92/181)
回答No.4

擬似コードではなくて、実際にテストに使っているコードを抜き出した方が良いですよ。 で、これ、各関数の戻り値や、エラーコードは全くチェックしていないんですか?

sav_moster
質問者

補足

■スレッドA int a = 0; int ret = 0; for(a = 0; a < 1000; a++){ fp = fopen("/var/tmp/test.dat", "w"); if (fp == NULL) { return ; } ret = fclose("/var/tmp/test.dat"); printf("fclose (%d")\n", ret); if( ret != 0) { return; } printf("remove start\n"); A-1 ret = remove("/var/tmp/test.dat"); A-2 printf("remove end (%d)\n", ret); A-3 } ■スレッドB int a = 0; int ret = 0; for(a = 0; a < 1000; a++){ rmdir("/var/tmp/etc/test1"); printf("mkdir start\n");  B-1 ret = mkdir("/var/tmp/etc/test1");  B-2 printf("mkdir end (%d)\n", ret); B-3 } とあり、ログは、何回かforが回った後、 remove star mkdir start とでて、"remove end" も "mkdir end"も返ってこない状態です。 ちなみにエラー処理には一度も落ちていませんし。 ret も常に0です。 以上よろしくお願いいたします。

回答No.3

> /varディレクトリにすらアクセスできなくなってしまいます。 > (cd var で lsコマンドを叩くと何も表示されないし、リターンもない) /varにアクセスができないということは、 ・なにかのプロセスが大量にvarをつかんでいる ・/varのファイルシステムが壊れかけている ということではないかと。 件のプロセス実行時のみこの現象がおきるのなら、前者なのでしょう。 もしかして mkdir するとき mkdir出来なかったらループするようにプログラムされていて そのループにタイムアウトも設定されていないのではないでしょうか? これだと、通常はプロセスの最後に掃除されるはずの "/var/tmp/etc/test1"が 処理の異常終了で消えずに残っていると、無限ループになりますよね。 もしくは、ロックのためにmkdirを使って排他処理はしているが、 ロックの順番が悪くて、デッドロック状態になっているとか。 たとえば、 プログラムAが /tmp/DIR1をmkdir(loop)してから、/tmp/DIR2をmkdir(loop) プログラムBが /tmp/DIR2をmkdir(loop)してから、/tmp/DIR1をmkdir(loop) が同時に動くと、 プログラムAはプログラムBが作ったDIR2が消えるまで、mkdirをループしますが、 プログラムBのほうも、プログラムAが作ったDIR1が消えるまでまつので、 結果、どちらも無限ループするデッドロック状態・・・とか。 なお、関係ないかもしれませんが、 remove("/var/test.dat") は/var/tmp/test.datでしょうか? (/var直下のファイルは、root権限がないと、ファイルを作ったり削除したりできないのでは?)

sav_moster
質問者

補足

ご回答ありがとうございます。 >は/var/tmp/test.datでしょうか? すみません。その通りです。 >もしかして mkdir するとき mkdir出来なかったらループするようにプログラムされていて >そのループにタイムアウトも設定されていないのではないでしょうか? は確認しましたが、大丈夫だと思います。 簡単にプログラムを書くと、以下のようになります。 これを同時に動かすと、(1)の後に(2)が実行されたログがでて、 そこで処理がストップしてしまいます。 cd /var/tmpとすると、ファイルシステムが壊れているいるためか コマンドもなにも受付なくなります。 ■スレッドA for(1000){ fp = fopen("/var/tmp/test.dat", "w"); if (fp == NULL) { return ; } fclose("/var/tmp/test.dat"); remove("/var/tmp/test.dat"); (1) } ■スレッドB for(1000){ rmdir("/var/tmp/etc/test1"); mkdir("/var/tmp/etc/test1"); (2) }

関連するQ&A