1

まず、コード:

lblFileNbr.Text = "?/?";
lblFileNbr.ToolTipText = "Searching for files...";
lock(_fileLock)
{
    _dirFiles = new string[0];
    _fileIndex = 0;
}
if(_fileThread != null && _fileThread.IsAlive)
{
    _fileThread.Abort();
}
_fileThread = new Thread(() =>
    {
        string dir = Path.GetDirectoryName(fileName) ?? ".";
        lock (_fileLock)
        {
            _dirFiles = GetImageFileExtensions().SelectMany(f => Directory.GetFiles(dir, f, _searchOption)).OrderBy(f => f).ToArray();
            _fileIndex = Array.IndexOf(_dirFiles, fileName);
        }
        int totalFileCount = Directory.GetFiles(dir, "*.*", _searchOption).Length;

        Invoke((MethodInvoker)delegate
        {
            lblFileNbr.Text = string.Format("{0}/{1}", NumberFormat(_fileIndex + 1), NumberFormat(_dirFiles.Length));
            lblFileNbr.ToolTipText = string.Format("{0} ({1} files ignored)", dir, NumberFormat(totalFileCount - _dirFiles.Length));
        });
    });
_fileThread.Start();

小さな画像表示プログラムを作成しています。画像を開くと、同じディレクトリ内のファイルの数が一覧表示されます。他の多くのファイル (たとえば 150K) を含むディレクトリで画像を開くと、ファイル リストの作成に数秒かかることに気付きました。したがって、このタスクを別のスレッドに委任しています。

ただし、ファイルの検索が完了する前に別の画像を開いた場合、その古いカウントはもはや関係ないため、スレッドを中止します。

写真を切り替えるためのいくつかの重要な機能を追加したいので、ロック_dirFilesしています。そのため、別の場所 (ただし UI スレッド内) にアクセスする必要があります。_fileIndexLeftRight

これは安全ですか?現在、C# でスレッドを処理する方法は数十あるようですが、単純なものが欲しかっただけです。


fileNameはローカル変数 (つまり、無名関数に「コピー」されるということですよね?) であり、_searchOption読み取り専用であるため、これら 2 つは安全にアクセスできると思います。

4

2 に答える 2

3

> このファイル検索スレッドを中止しても安全ですか?

短い答えはノーです!

スレッドを中止することはほとんど安全ではありません。このアドバイスは、ネイティブ コードを実行している可能性がある場合にさらに当てはまります。

協力して十分速く終了できない場合 ( への呼び出しにDirectory.GetFiles時間がかかるため)、最善の策はスレッドを放棄することです。スレッドをきれいに終了させますが、その結果は無視します。

いつものように、Joe Albahari の無料の電子ブックを読むことをお勧めします

于 2012-06-10T19:16:59.847 に答える
1

Thread.Abort() を使用してスレッドを中止するのは安全ではありません。しかし、代わりに独自のアボートを実装することもできます。これにより、制御された方法でスレッドを安全に終了させることができます。

GetFiles の代わりに EnumerateFiles を使用すると、カウンターをインクリメントしてファイルの総数を取得しながら、フラグをチェックしてスレッドを中止する必要があるかどうかを確認しながら、各ファイルをループできます。

現在の GetFiles().Length の代わりに次のようなものを呼び出します。

private bool AbortSearch = false;
private int NumberOfFiles(string dir, string searchPattern, SearchOption searchOption)
{
    var files = Directory.EnumerateFiles(dir, searchPattern, searchOption);
    int numberOfFiles = 0;
    foreach (var file in files)
    {
        numberOfFiles++;

        if (AbortSearch)
        {
            break;
        }
    }
    return numberOfFiles;
}

その後、置き換えることができます

_fileThread.Abort();

AbortSearch=true;
_fileThread.Join();

現在の Thread.Abort() で現在の状態を達成できますが、必要なときにすべてのスレッドを正常に終了させることができます。

于 2012-06-11T10:55:40.487 に答える