【发布时间】:2010-02-17 16:03:03
【问题描述】:
我试图让我的 GUI 线程在长时间运行的操作中保持响应式。这些操作必须是同步的,因为它们通常是在请求的操作完成之前需要完成的操作。
我试图通过后台工作人员、监视器和锁定对象来执行此操作。本质上,我想在启动长时间运行的进程之前启动一个计时器,在后台线程中启动长时间运行的进程并在后台工作线程上等待以表示它已经完成,然后再继续依赖代码。如果长时间运行的过程花费的时间太长,则向用户显示“正在加载...”对话框,以便他们知道应用程序没有崩溃。
这方面的一个例子可能是图形包中的用户单击按钮,必须先从磁盘加载大图像,然后才能绘制图像,然后打印计算到顶部一百万位小数的 pi。
我无法从磁盘异步加载图像,这将使 UI 保持响应,因为用户可能会启动另一个会扰乱程序状态的操作(即撤消操作)。
我可以简单地将光标更改为沙漏并完成它,但在许多情况下,我希望用户也能够取消操作 - “正在加载.. ." 带有取消按钮的对话可以很好地解决这个问题。
我最初的目标是使用锁定对象和System.Threading.Monitor.Enter(),以便 UI 线程等到长时间运行的线程完成,然后继续执行。如果计时器在长时间运行的线程完成之前触发,则 UI 线程仍可用于处理事件并在屏幕上绘制对话框。
我遇到的问题是,在 UI 线程尝试获取锁定之前,我无法让后台工作人员锁定对象。
相当烦人的是,我正在使用一些非常黑盒的第 3 方代码来进行处理。因此,我无法将代码定制为线程友好并报告其进度或支持取消。
我的问题
是否有任何行之有效的方法来包装第 3 方代码,以便 UI 线程保持响应,并且如果需要我可以显示取消对话? - 在许多情况下,长时间运行的操作几乎立即完成并且不需要显示对话框。
进一步澄清
我为什么要这样做?异步操作是 Windows 应用程序的宠儿...
好吧,我不想在启动长时间运行的异步操作时锁定用户界面的各个方面,然后在完成后解锁各个方面。我可以 - 通过设置光标或物理禁用所有按钮等,但实际上我更希望能够简单地将调用包装在“某些对象/方法等”中,这将允许弹出一个对话框,如果(并且仅当)操作花费的时间足够长以影响用户。我不必担心执行流程的变化,我仍然(总体上)能够在代码中维护原子操作(而不是在回调中拆分)并且仍然有一个“响应式”用户界面。
我可以理解为什么到目前为止我在将 BackgroundWorker / Thread 制作成同步阻塞线程方面没有成功,但我确实担心我将不得不在 GUI 线程中走while(true){ sleep() } 路线而不是而不是使用锁。
【问题讨论】:
-
为什么你不能从磁盘(或其他第三方代码)异步加载图像(例如 BackgroundWorker 执行或你自己的显式线程方法)?它必须在 UI 线程上执行吗?
-
如果您可以完全避免它,请不要在最终用户注意到的任何时间段内保持同步对象。将它们视为稀缺资源,就像 SQL 事务一样。
-
顺便说一句,C# 是一种没有线程的编程语言。
标签: c# .net multithreading locking