13

C で並べ替えプログラムを作成する必要があり、ディスク領域を節約するためにファイルを適切な場所で並べ替えることができれば便利です。データは貴重なので、プロセスが中断された場合 (ctrl-c) にファイルが破損しないようにする必要があります。マシンの電源コードが引っ張られないことを保証できます。

その他の詳細: ファイルは最大 40 GB、レコードは 128 ビット、マシンは 64 ビット、OS は POSIX

これを達成するためのヒント、または一般的なメモはありますか?

ありがとう!

明確にするために:ユーザーはプロセスをctrl-cしたいと思うでしょう。この場合、正常に終了し、データが安全であることを確認したいと考えています。したがって、この質問は、割り込みの処理と、要求された場合にすばやく終了できる並べ替えアルゴリズムの選択に関するものです。

フォローアップ(2年後):後世のために、SIGINTハンドラーをインストールしましたが、うまく機能しました。これで電源障害を防ぐことはできませんが、対処できるリスクです。https://code.google.com/p/pawnsbfs/source/browse/trunk/hsort.cおよびhttps://code.google.com/p/pawnsbfs/source/browse/trunk/qsort.cのコード

4

6 に答える 6

12

Jerry の言う通り、気になるのが Ctrl-C だけなら、一度に一定期間 SIGINT を無視することができます。一般的にプロセスの死に対して証明したい場合は、何らかの最小限のジャーナリングが必要です。2 つの要素を交換するには:

1) ファイルの末尾または別のファイルの制御構造にレコードを追加し、ファイルのどの 2 つの要素 A と B を交換するかを示します。

2) A をスクラッチ スペースにコピーし、コピーしたことを記録して、フラッシュします。

3) B を A の上にコピーし、コピーしたことをスクラッチ スペースに記録し、フラッシュします。

4) B 上のスクラッチ スペースからコピーします。

5) レコードを削除します。

これは、すべての実用的な目的で O(1) の余分なスペースであるため、ほとんどの定義ではインプレースとしてカウントされます。理論的には、n を任意に大きくできる場合、インデックスを記録すると O(log n) になります。実際には、これは非常に小さい log n であり、合理的なハードウェア/実行時間により、64 より上に制限されます。

すべての場合において、「フラッシュ」と言うときは、変更を「十分に」コミットすることを意味します。基本的なフラッシュ操作では、プロセス内のバッファーのみをフラッシュすることがありますが、実際には物理メディアを同期しません。これは、OS/デバイス ドライバー/ハードウェア レベル全体でバッファーをフラッシュしないためです。プロセスの停止だけを心配している場合はこれで十分ですが、突然のメディアのマウント解除が心配な場合は、ドライバーをフラッシュする必要があります。停電が心配な場合は、ハードウェアを同期する必要がありますが、そうではありません。UPS を使用している場合、または停電が非常にまれで、データが失われても構わないと思う場合は、それで問題ありません。

起動時に、「スワップ進行中」のレコードがないかスクラッチ スペースを確認します。見つかった場合は、どこまで到達したかを調べ、そこからスワップを完了して、データを健全な状態に戻します。次に、並べ替えをやり直します。

以前の 2 倍のレコードの書き込みを行っており、フラッシュ/同期には驚くほどコストがかかる可能性があるため、ここには明らかにパフォーマンスの問題があります。実際には、インプレースソートには、多くのスワップを伴う複合的な移動操作が含まれる場合がありますが、すべての要素がスクラッチスペースにヒットするのを回避するために最適化できます。データを上書きする前に、そのコピーを安全な場所に保管し、各要素のコピーが 1 つだけ含まれる状態にファイルを戻すために、そのコピーの保存先を記録しておく必要があります。

Jerry の言うとおり、真のインプレース ソートはほとんどの実用的な目的には難しすぎて時間がかかりすぎます。元のファイル サイズの線形分数をスクラッチ スペースとして確保できる場合は、マージ ソートを使用する方がはるかに効率的です。

明確化に基づいて、インプレースソートを使用してもフラッシュ操作は必要ありません。異常終了後の起動時に復元するのではなく、終了するにデータを安全に取得するために SIGINT ハンドラーがアクセスできる、同じように機能するメモリ内のスクラッチ スペースが必要であり、シグナルでそのメモリにアクセスする必要があります。安全な方法 (技術的には、どの変更が行われたかを示すフラグを使用することを意味します)。それでも、真のインプレースソートよりもマージソートを使用したほうがよいでしょう。sig_atomic_t

于 2010-09-07T13:24:02.753 に答える
5

SIGINT「プロセスはすぐに終了する必要があります」フラグを設定するだけのハンドラーをインストールします。

ソートでは、2つのレコードがスワップされるたびに(またはNがスワップされるたびに)フラグを確認します。フラグが設定されている場合は、救済します。

于 2010-09-07T14:42:01.923 に答える
5

ctrl-c から保護する部分は非常に簡単です: signal(SIGINT, SIG_IGN);.

並べ替え自体に関する限り、通常、マージ並べ替えは外部並べ替えに適しています。基本的な考え方は、できるだけ多くのレコードをメモリに読み込み、並べ替えてからディスクに書き戻すことです。これを処理する最も簡単な方法は、各実行をディスク上の個別のファイルに書き込むことです。次に、それらをマージして戻します。各実行の最初のレコードをメモリに読み取り、それらの最小のものを元のファイルに書き込みます。そのレコードを提供した実行から別のレコードを読み取り、完了するまで繰り返します。最後のフェーズは、元のファイルを変更する唯一の時間であるため、中断などに対して本当に保証する必要があるのはこのときだけです。

別の可能性は、選択ソートを使用することです。悪い点は、ソート自体がかなり遅いことです。良い点は、余分なスペースをあまり使わずに、ほとんど何でも生き残るように書くのがとても簡単だということです。一般的な考え方は非常に単純です。ファイル内の最小のレコードを見つけて、それを最初の場所に入れ替えます。次に、残っている最小のレコードを見つけて、それを 2 番目のスポットに入れ替え、というように、完了するまで繰り返します。これの良い点は、ジャーナリングが簡単だということです。スワップを行う前に、スワップしようとしている 2 つのレコードの値を記録します。並べ替えは最初のレコードから最後のレコードまで実行されるため、他に追跡する必要があるのは、任意の時点で既に並べ替えられているレコードの数だけです。

于 2010-09-07T13:31:29.267 に答える
3

ヒープ ソートを使用し、各スワップ操作中の中断 (ブロック シグナルなど) を防ぎます。

于 2010-09-07T13:18:51.770 に答える
0

変更する予定があるものは何でもバックアップします。ソートが成功したことを示すフラグを立てます。すべてが OK の場合は結果を保持し、それ以外の場合はバックアップを復元します。

于 2010-09-07T13:20:42.107 に答える
-1

64ビットOSを想定すると(64ビットマシンであると言われましたが、32ビットOSを実行している可能性があります)、mmapを使用してファイルを配列にマップし、配列でqsortを使用できます。

SIGINT のハンドラーを追加して msync と munmap を呼び出し、アプリがデータを失うことなく Ctrl-C に応答できるようにします。

于 2010-09-07T15:15:06.377 に答える