使用计时器的长时间运行任务会挂起UI [英] Long running task with timers hangs UI

查看:129
本文介绍了使用计时器的长时间运行任务会挂起UI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个长时间运行的任务,它通过蓝牙在远程设备上执行诊断测试列表。点击按钮开始测试。

我使用单个线程[在MainForm中]迭代执行下面同步的测试对象集合:

1.更新每个测试的UI [在MainForm中]。

2.将测试命令发送到设备[由单独的类BTest.cs处理]



BTest.cs中的计时器在发送命令后立即开始计算测试持续时间。



如果测试成功执行,BTest.cs会发起一个事件。这是在MainForm中捕获的,测试结果更新为UI。



使用单线程和UI调用方法的当前实现....冻结UI直到线程完成其任务。



非常感谢任何不冻结UI的替代解决方案。在此先感谢。

I have a long running task which performs a list of diagnostic tests on a remote device via Bluetooth. The test starts on a button click.
I have used a single thread[in MainForm] to iterate through a collection of test objects performing the below synchronously:
1. update UI for each test [in MainForm].
2. send test command to the device [handled by a separate class BTest.cs]

A timer in BTest.cs starts calculating test duration as soon as command is sent.

If test executed successfully, BTest.cs raised an event. This is captured in MainForm and test results are updated to UI.

Current implemention using single thread and invoke method for UI....freezes UI until thread completes its task.

Any alternate solution that does not freeze UI is much appreciated. Thanks in advance.

推荐答案

长时间运行的任务是使用线程完成的,而不是使用计时器。在UI下执行如此长时间运行的任务的额外线程的唯一一个小问题是您无法直接从该线程操作UI。使用UI线程调用机制解决了这个问题。



您无法从非UI线程调用与UI相关的任何内容。相反,您需要使用 Invoke System.Windows.Threading的方法。 Dispatcher (对于Forms或WPF)或 System.Windows.Forms.Control (仅限表单)。



您将在我过去的答案中找到有关其工作原理和代码示例的详细说明:

Control.Invoke()与Control.BeginInvoke() [ ^ ],

使用Treeview扫描仪和MD5的问题 [ ^ ]。



另请参阅有关线程的更多参考资料:

如何让keydown事件在不同的操作上运行vb.net中的线程 [ ^ ],

在启用禁用+多线程后控制事件未触发 [ ^ ]。



现在,最方便的是创建一个永久线程并使用事件等待句柄来限制它。此外,在线程包装器中封装所有这些以及所有同步和调用机制非常方便。这样,线程可以在任务即将到来时重用。请查看我过去的答案:

使代码线程安全 [ ^ ] ,

正好运行一个Web服务中永远不会终止的作业/线程/进程(asp.net) [ ^ ],

暂停正在运行的线程 [ ^ ],

线程中的ManualResetEvent和AutoResetEvent [ ^ ]。



在线程包装器上,另请参阅:

如何将ref参数传递给线程 [ ^ ],

更改参数线程(生产者)启动后的情况 [ ^ ],

穆尔用C#进行演讲 [ ^ ]。



此外,您可以使用阻塞队列将某些任务推送到线程包装器(然后不需要偶数线程处理程序,它被封装在队列中,可以是直接表示这些任务的委托实例的队列。我的文章解释了这一点:用于线程通信和Inter-的简单阻塞队列线程调用 [ ^ ]。



使用.NET v.4及更高版本,您可以使用已在.NET FCL中实现的更快的阻塞队列: http://msdn.microsoft.com/en-us/library/dd267312%28v = vs.110%29.aspx [ ^ ]。



-SA
Long running tasks are done using threads, not timers. The only one little problem with having some extra thread performing such a long running task under the UI is that you cannot directly operate UI from that thread. This problem is solved using UI thread invocation mechanism.

You cannot call anything related to UI from non-UI thread. Instead, you need to use the method Invoke or BeginInvoke of System.Windows.Threading.Dispatcher (for both Forms or WPF) or System.Windows.Forms.Control (Forms only).

You will find detailed explanation of how it works and code samples in my past answers:
Control.Invoke() vs. Control.BeginInvoke()[^],
Problem with Treeview Scanner And MD5[^].

See also more references on threading:
How to get a keydown event to operate on a different thread in vb.net[^],
Control events not firing after enable disable + multithreading[^].

Now, it's most convenient to create a permanent thread and throttle it by using a event wait handle. Also, it is very convenient to encapsulate all that and also all synchronization and invocation mechanisms in a thread wrapper. This way, the thread can be reused as tasks are coming up. Please see my past answers:
Making Code Thread Safe[^],
Running exactly one job/thread/process in webservice that will never get terminated (asp.net)[^],
pause running thread[^],
ManualResetEvent and AutoResetEvent in Thread[^].

On the thread wrappers, see also:
How to pass ref parameter to the thread[^],
Change parameters of thread (producer) after it is started[^],
MultiThreading in C#[^].

Also, you can use a blocking queue for pushing some tasks to the thread wrapper (then the even thread handler is not needed, it is encapsulated in the queue, which can be a queue of delegate instances representing those tasks directly). This is explained in my article: Simple Blocking Queue for Thread Communication and Inter-thread Invocation[^].

With .NET v.4 and later, you can use faster blocking queue already implemented in .NET FCL: http://msdn.microsoft.com/en-us/library/dd267312%28v=vs.110%29.aspx[^].

—SA


在Windows操作系统中,当WM_PAINT消息发送到应用程序时,UI会刷新。但是消息队列中的消息具有优先级 - WM_PAINT具有最低优先级,因此它将等待直到有其他消息...

您最好转到多线程应用程序并学习如何在线程之间更新UI。 ..

您可以从这里开始: http://msdn.microsoft.com /en-us/magazine/cc300429.aspx [ ^ ]。
In Windows OS the UI refreshes when WM_PAINT message is sent to application. But messages in message queue has a priority - WM_PAINT has the lowest, so it will wait until have other messages...
You better move to multi-threaded application and learn how to update UI between threads...
You may start here: http://msdn.microsoft.com/en-us/magazine/cc300429.aspx[^].


谢谢大家。我使用手动重置事件等待每次测试的通知。现在我的应用程序正常工作。
Thank you all. I used manual reset event to wait for notification from each test. Now my app works.


这篇关于使用计时器的长时间运行任务会挂起UI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆