报告线程进度的最佳方式
我有一个程序,它使用线程顺序执行耗时的进程。我希望能够像 BackgroundWorker.ReportProgress
/ProgressChanged
模型那样监视每个线程的进度。由于我受到其他限制,我无法使用 ThreadPool
或 BackgroundWorker
。允许/公开此功能的最佳方式是什么?重载 Thread 类并添加属性/事件?另一个更优雅的解决方案?
I have a program that uses threads to perform time-consuming processes sequentially. I want to be able to monitor the progress of each thread similar to the way that the BackgroundWorker.ReportProgress
/ProgressChanged
model does. I can't use ThreadPool
or BackgroundWorker
due to other constraints I'm under. What is the best way to allow/expose this functionality. Overload the Thread
class and add a property/event? Another more-elegant solution?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果“重载”实际上是指继承,那么就不行。
Thread
是密封的,因此无法继承,这意味着您将无法向其添加任何属性或事件。创建一个类来封装线程将执行的逻辑。添加可用于从中获取进度信息的属性或事件(或两者)。
更新:
让我更清楚地说明为什么在这种情况下需要内存屏障。屏障防止读取被移动到其他指令之前。最有可能的优化不是来自 CPU,而是来自 JIT 编译器,将
Progress
的读取“提升”到while
循环之外。这种运动给人一种读起来“陈旧”的印象。这是该问题的半现实演示。必须在没有 vshost 进程的情况下运行发布版本。任何一个都会禁用显示错误的优化(我相信这在框架版本 1.0 和 1.1 中也无法重现,因为它们的优化更原始)。错误在于“已停止”从未显示,即使它显然应该显示。现在,取消对 Thread.MemoryBarrier 的调用的注释并注意行为的变化。另请记住,即使是对此代码结构进行最细微的更改,目前也会抑制编译器进行相关优化的能力。其中一项更改是实际调用委托。换句话说,您目前无法使用空检查和调用模式来重现过时的读取问题,但 CLI 规范中没有任何内容(我无论如何都知道这一点) ),禁止未来假设的 JIT 编译器重新应用该“提升”优化。
If by "overload" you actually mean inherit then no. The
Thread
is sealed so it cannot be inherited which means you will not be able to add any properties or events to it.Create a class that encapsulates the logic that will be executed by the thread. Add a property or event (or both) which can be used to obtain progress information from it.
Update:
Let me be a little more clear on why a memory barrier is necessary in this situation. The barrier prevents the read from being moved before other instructions. The most likely optimization is not from the CPU, but from the JIT compiler "lifting" the read of
Progress
outside of thewhile
loop. This movement gives the impression of "stale" reads. Here is a semi-realistic demonstration of the problem.It is imperative that a Release build is ran without the vshost process. Either one will disable the optimization that manifest the bug (I believe this is not reproducable in framework version 1.0 and 1.1 as well due to their more primitive optimizations). The bug is that "Stopped" is never displayed even though it clearly should be. Now, uncomment the call to
Thread.MemoryBarrier
and notice the change in behavior. Also keep in mind that even the most subtle changes to the structure of this code currently inhibit the compiler's ability to make the optimization in question. One such change would be to actually invoke the delegate. In other words you cannot currently reproduce the stale read problem using the null check followed by an invocation pattern, but there is nothing in the CLI specification (that I am aware of anyway) that prohibits a future hypothetical JIT compiler from reapplying that "lifting" optimization.我前一段时间尝试过,它对我有用。
List
的带有锁的类。Timer.Tick
事件中编写代码以读取线程输出的消息。I tried this some time ago and it worked for me.
List
-like class with locks.Timer.Tick
event to read the messages the threads output.您可能还想查看基于事件的异步模式。
You might also want to check out the Event-based Asynchronous Pattern.
为每个线程提供一个返回状态对象的回调。您可以使用线程的
ManagedThreadId
来跟踪单独的线程,例如将其用作Dictionary
的键。您可以从线程处理循环中的多个位置调用回调,或者从线程内触发的计时器调用它。您还可以使用回调的返回参数来指示线程暂停或停止。
我使用回调取得了巨大成功。
Provide each thread with a callback that returns a status object. You can use the thread's
ManagedThreadId
to keep track of separate threads, such as using it as a key to aDictionary<int, object>
. You can invoke the callback from numerous places in the thread's processing loop or call it from a timer fired from within the thread.You can also use the return argument on a callback to signal the thread to pause or halt.
I've used callbacks with great success.