在多线程环境中,应用程序在删除大文件时挂起

问题描述 投票:0回答:1

在我的应用程序中,我正在执行大量文件的删除,当我单击“删除”按钮时,我的应用程序UI被挂起,直到删除完成。

这里是导致挂起的方法。

  /// <summary>
  /// Attempts to acquire the CountDown, timing out after a specified
  /// interval.
  /// </summary>
  /// <param name="timeout">The maximum time to wait.</param>
  /// <returns>
  /// Boolean true if the CountDown was acquired.  Boolean false if the
  /// method timed out.
  /// </returns>
  public bool Attempt(TimeSpan timeout)
  {
     lock (this)
     {
        if (_count <= 0) return true;
        if (timeout <= TimeSpan.Zero) return false;

        TimeSpan waitTime = timeout;
        DateTime start = DateTime.Now;
        for (; ; )
        {
           // if the thread has been interrupted, Wait() will throw
           // ThreadInterruptedException()
           Monitor.Wait(this, waitTime);
           if (_count <= 0) return true;
           waitTime = timeout - (DateTime.Now - start);
           if (waitTime <= TimeSpan.Zero) return false;
        }
     }
  }

我执行的步骤:

  1. 从应用程序的窗口表单中单击按钮“ btnDel”。

  2. 然后应用程序进入挂起模式。

  3. 我单击全部破坏(Ctrl + Alt + Break)。

当从VS中按下Break All时,它停留在Monitor.Wait(this, waitTime);,它开始等待完成,并且我无法执行任何其他UI操作。

我正在阅读MSDN文章,其中有一些使用Monitor类管理线程的示例,但我认为我缺少一些内容。

有什么方法可以使用户界面不受此后台删除操作的影响?

我希望在后台执行此删除操作时执行其他UI操作。

非常感谢您的帮助,谢谢。

c# multithreading monitor ui-thread background-thread
1个回答
0
投票

这里有一些对我有用的方法:结合使用CancellationToken和SemaphoreSlim互斥对象以保持线程安全,这样我们就不必在运行时阻止UI线程。

CancellationTokenSource _cts = null;
SemaphoreSlim ssBusy = new SemaphoreSlim(2);
private void DeleteManyFiles()
{
    try
    {
        ssBusy.Wait();
        switch (ssBusy.CurrentCount)
        {
            case 1:
                _cts = new CancellationTokenSource();
                for (int i = 0; i < NUMBER_OF_FILES_TO_DELETE; i++)
                {
                    bool cancelled = DeleteSingleFile(_cts.Token);
                }
                break;
            case 0:
                // A count of 0 indicates that the operation is already in progress.
                MessageBox.Show("Deletion is already in progress");
                break;
            default:
                break;
        }
    }
    catch(Exception ex)
    {
        Debug.Assert(false, ex.Message);
    }
    finally
    {
        ssBusy.Release();
    }
}

......

    private bool DeleteSingleFile(CancellationToken ct)
    {
        if(ct.IsCancellationRequested)
        {
            return true;
        }
        // Simulate half a second to delete one file
        Task.Delay(500).Wait();
        // SIMULATE ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

        // Decrement remaining count
        _remaining--;

        // Notify the UI thread
        FileDeleted?.Invoke(this, EventArgs.Empty);
        return false;
    }
    event EventHandler FileDeleted;

我将完整的工作示例发布在我们的GitHub上。您可以浏览或单击Clone or Download,如果这对您有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.