c# - 当应用程序退出时,如何等待我的异步操作完成?

标签 c# wpf asynchronous task-parallel-library

如果用户执行删除项目等操作,它会立即从 UI 中删除它们,然后使用 TPL 在后台线程上将它们从数据库中删除。问题是,如果用户在后台线程结束之前退出应用程序,则该项目实际上不会被删除。

在关闭应用程序之前是否有等待异步操作完成的标准方法?

我的异步调用是这样的:

if (MyObjectList.Contains(obj)) MyObjectList.Remove(obj);
Task.Factory.StartNew(() => DAL<MyEntities>.DeleteObject(obj));

更新

这是我使用的最终代码。我很高兴看到它按预期工作,但如果我可以改进它,请告诉我。我还有很多东西要学:)

public partial class App : Application
{
    private List<Task> _backgroundTasks = new List<Task>();

    public App()
    {
        EventSystem.Subscribe<TaskStartedMessage>((e) =>
        {
            _backgroundTasks.Add(e.Task);
        });

        EventSystem.Subscribe<TaskEndedMessage>((e) =>
        {
            if (_backgroundTasks.Contains(e.Task))
                _backgroundTasks.Remove(e.Task);
        });
    }

    protected override void OnExit(ExitEventArgs e)
    {
        Task.WaitAll(_backgroundTasks.Where(p => !p.IsCompleted).ToArray(), 30000);

        base.OnExit(e);
    }
}

当开始一个重要的后台任务时,我使用了这个语法:

var task = Task.Factory.StartNew(() => DAL<MyEntities>.DeleteObject(obj));
EventSystem.Publish<TaskStartedMessage>(new TaskStartedMessage(task));
await task;
EventSystem.Publish<TaskEndedMessage>(new TaskEndedMessage(task));

我为 await/async 使用 AsyncCTP,为事件系统使用 Microsoft Prism 的 EventAggregator

最佳答案

没有标准方法,但由于您在此处创建了一个特定任务,因此应该很容易将其放入列表并构建一些退出逻辑以等待该列表中的所有任务。

好的,一个示例。未经测试且不完整:

// untested
static class CriticalTasks
{
    static HashSet<Task> tasks = new HashSet<Task>();
    static object locker = new object();

    // when starting a Task
    public static void Add(Task t)
    {
        lock(locker)
           tasks.Add(t);
    }

    // When a Tasks completes
    public static void Remove(Task t)
    {
        lock(locker)
           tasks.Remove(t);
    }

    // Having to call Remove() is not so convenient, this is a blunt solution. 
    // call it regularly
    public static void Cleanup()
    {
        lock(locker)
           tasks.RemoveWhere(t => t.Status != TaskStatus.Running);
    }

    // from Application.Exit() or similar. 
    public static void WaitOnExit()
    {
        // filter, I'm not sure if Wait() on a canceled|completed Task would be OK
        var waitfor = tasks.Where(t => t.Status == TaskStatus.Running).ToArray();
        Task.WaitAll(waitfor, 5000);
    }
}


缺点是您必须使用代码扩展每个任务以添加和删除它。

忘记 Remove() (例如,当异常发生时)将是一个(小的)内存泄漏。这不是太关键,除了使用 using() block 给代码增加负担之外,您还可以定期运行 Cleanup() 方法,该方法使用 HashSet.RemoveWhere() 来删除未运行的任务。

关于c# - 当应用程序退出时,如何等待我的异步操作完成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8617058/

相关文章:

javascript - 异步函数不按进程顺序工作

java - Spring:Servlet 3.1 + SockJS = 必须启用异步支持

c# - 在 C# 中使用动态 "binding expression"格式化字符串

c# - 如何使用 LINQ to SQL 类的 PropertyChangedEventHandler 进行即时更新?

c# - 有趣的 OutOfMemoryException 与 StringBuilder

.net - ItemsControl 绑定(bind)当前对象?

wpf - 如何在选择列表框中的项目时打开新的用户控件?

javascript - 如何从异步调用返回响应?

c# - .NET Core DI,为包注册默认实现

c# - xamarin 中的 VPN 客户端