应用程序暂停时访问UI线程?

时间:2017-12-12 10:14:06

标签: c# multithreading uwp windows-10-universal suspend

我有一个UWP应用程序,允许用户创建和修改文本文档。我很难让保存机制与app暂停/恢复生命周期一起使用。

这就是我所拥有的:

  1. 所有磁盘访问都在单独的后台线程上完成,以保持UI响应
  2. 该后台线程还序列化所有磁盘访问,以确保始终只进行一次读取或写入操作
  3. 保存文档之前和之后,UI会更新以指示正在进行保存。这是通过Dispatcher.RunAsync()
  4. 在UI线程上安排的

    暂停应用时:

    • 暂停时,我必须最后一次保存文档以确保所有更改都在磁盘上(应用可能会在暂停时终止)
    • 所以我要求ExtendedExecutionSession
    • 我在队列中安排了一个最终的保存操作
    • 然后我等待队列处理所有挂起的磁盘访问操作
    • 最后,我将扩展执行会话标记为已完成

    我的问题:

    • 已计划的保存操作完成其磁盘访问,然后尝试通过Dispatcher.RunAsync()更新主线程上的UI。后台队列等待此任务完成,但它永远不会,因为到那时,UI线程已经停止

    →因此我的最终保存操作永远不会执行,因为后台队列等待更新UI。

    这是一个流程图:

    App suspension flow chart

    出现了一些问题:

    1. 当应用程序被暂停时,UI线程是否完全停止?只有当它闲置或者在#34;之间什么?即如果我通过Dispatcher.RunAsync()安排了一个阻止,这至少会完成或者#34;冻结"?
    2. 我有办法检查当前窗口的UI线程是否已经停止,以便我知道在后台文件访问线程中我不能再访问它了吗?
    3. 当某个应用被暂停时,哪些线程会停止播放?
    4. 我的后台文件访问线程在应用程序被暂停时是否也有被阻止的风险?
    5. 总结问题:

      当应用程序被暂停时,我必须确保我等待后台线程上可能正在挂起的磁盘访问才能完成,然后我再次保存文档,以防我的应用程序稍后终止。

1 个答案:

答案 0 :(得分:4)

这听起来太熟悉了!

我从您的问题中了解到,保存操作以更新UI结束,但由于它在后台线程中运行,因此除非您使用Dispatcher进行安排,否则无法触及UI。只是为了可视化,您的代码看起来像这样:

public async Task SaveAsync()
{
   // .. save to disk ..

   await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
   {
      // update UI here
   }

   // Save Complete!
}

如果是这样,问题是UI更新是排队后台操作的一部分,如果UI更新或Dispatcher本身阻止了任何内容,则在到达该行之前不会开始其他操作{ {1}},如果//Save Complete!从未执行您的操作,则永远不会发生。

不要考虑使用UI更新的保存操作,而是尝试公开将触发UI更新的事件。例如:

Dispatcher

您的视图可以将处理程序附加到这些事件并显示/隐藏相应的视觉效果,而您的暂停处理程序可以安全地调用public event EventHandler SaveStarted; public event EventHandler SaveCompleted; public async Task SaveAsync() { SaveStarted?.Invoke(this, EventArgs.Empty); // .. save to disk .. SaveCompleted?.Invoke(this, EventArgs.Empty); } 方法而无需担心UI。

当视图为SaveAsync()时,请确保分离这些事件处理程序。在提出这些事件时,您的保存操作不会阻止队列。

更新1

是的,您的事件处理程序必须使用Unloaded

在UI线程上运行
Dispatcher

因为处理程序被强制返回public void OnSaveCompleted(object sender, EventArgs e) { Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { // update UI here... } } ,所以它不会阻止后台线程。

更新2

听起来你有一些紧密耦合。您需要重新设计应用程序,使文本文档逻辑位于单独的项目中。我总是在 .Net Standard 项目中编写代码,强制所有用户界面输出。该项目将不允许任何UI代码,从而保持您的逻辑清洁和分离。

如果您的所有代码都位于UWP项目中,那么开始包含视图逻辑,XAML控件以及在您的情况下,应用程序中与演示无关的void非常容易。< / p>

在您的情况下,您需要弄清楚如何使文本文档逻辑成为文档状态的所有者,而不是UI。 Dispatcher只能由拥有hasChanges的相同逻辑修改。如果在UI操作期间某些东西中断/阻塞/失败/等并且它永远不会成功到文本文档,那么它是一个不完整的操作,不应该是文档的一部分,也不应该担心文档的责任什么时候暂停&amp;保存到磁盘。

如果UWP在其中一项操作中因任何原因导致您的应用程序被杀,那么它就消失了。您的下一个任务是弄清楚当应用程序再次唤醒时如何恢复此操作。