中止此文件搜索线程是否安全?

时间:2012-06-10 17:21:29

标签: winforms multithreading thread-safety thread-abort

首先,代码:

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_fileIndex因为我想添加一些 Left Right 键功能来切换照片,所以我将不得不访问其他地方(但在UI线程中)。

这样安全吗?现在似乎有很多处理C#中线程的方法,我只是想要一些简单的东西。


fileName是一个局部变量(这意味着它将被“复制”到匿名函数中,对吧?),_searchOption是只读的,所以我想这两个是安全的。< / p>

2 个答案:

答案 0 :(得分:3)

  

&GT;中止此文件搜索线程是否安全?

简短的回答是 NO!

中止线程几乎绝对不安全,而且当您执行本机代码时,此建议会更加适用。

如果你不能以足够快的速度合作退出(因为你需要花费时间调用Directory.GetFiles),最好的办法就是放弃线程:让它干净利落地完成,但忽略其结果。

与往常一样,我建议您阅读Joe Albahari's free ebook

答案 1 :(得分:1)

使用Thread.Abort()中止线程是不安全的。但你可以改为实现自己的中止,这可以让你以受控的方式安全地关闭线程。

如果使用EnumerateFiles而不是GetFiles,则可以在递增计数器时循环遍历每个文件,以获取文件总数,同时检查标志以查看线程是否需要中止。

调用此类内容代替当前的GetFiles()。长度:

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()来实现你的目标,但你可以允许所有线程在你想要的时候干净利落地结束。