我有一个应用程序,用户在其中提供要由线程处理的数据,然后线程将数据返回到UI。用户可以从另一个线程开始更改输入。如何正确忽略旧的重用线程?
我注意到经常有两种解决方案。 1)在调用中检查当前输入数据是否与所处理的线程相同 2)等待第一个线程结束,然后再开始另一个线程
第一个解决方案有效,但是如果用户再次将输入更改为相同的值并且使用相同的数据获得两次或更多次刷新的UI,则可能仍使用旧线程 第二个选项的响应性较差,尤其是当线程中的计算运行时间较长时,因为我们必须等待每个线程完成其工作
我创建了以下解决方案,我想知道这是否是正确的解决方法,还是我需要添加其他检查或锁定。
private Thread lastThread;
private void ButtonClick(object sender, MouseButtonEventArgs e)
{
this.lastThread= new Thread(delegate () { Update(someData); });
this.lastThread.Start();
}
private void Update(int someData) {
Thread currThread = Thread.CurrentThread;
Application.Current.Dispatcher.Invoke(new Action(() => EndUpdate(
someDataCalculated,
currThread
)));
private void EndUpdate(int someDataCalculated, Thread senderThread) {
if (senderThread == this.lastThread)
{
// right thread, do some work in UI
}
}
答案 0 :(得分:3)
如果用户调用了几个线程,并且可以更新其中任何一个的数据, 我认为您应该添加LastUpdated属性。 并跟踪用户何时进行更改,并以此来比较线程。
答案 1 :(得分:1)
您应该使用专门设计用于处理这类事情的工具-并且它应该是Microsoft的Reactive Framework。
您可以编写以下代码:
public MainWindow()
{
InitializeComponent();
IDisposable subscription =
Observable
.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(
h => Button.MouseLeftButtonDown += h,
h => Button.MouseLeftButtonDown -= h)
.Select(x => Observable.Start(() => { Update(42); return 42; }))
.Switch()
.ObserveOnDispatcher()
.Subscribe(x =>
{
// latest result only, do some work in UI
});
}
这通过在后台线程上调用MouseLeftButtonDown
来响应Update(42); return 42;
事件。然后,它调用.Switch()
,这是一个特殊的运算符,可确保仅返回对Observable.Start(() => { Update(42); return 42; })
的最新调用的结果(它忽略任何先前的结果,无论它们是否排在前)。然后,它使用.ObserveOnDispatcher()
运算符编组回UI。最后,.Subscribe(x =>
允许UI响应UI线程上返回的值。
请记住,您在问题中的示例代码尚未完全充实,因此我对此稍加捏造,但我认为您明白了。
在.Dispose()
上调用subscription
会分离事件处理。
只需NuGet“ System.Reactive.Windows.Threading”即可获取这些位,并将using System.Reactive.Linq;
添加到代码中即可获取所需的扩展方法。
如果您需要进一步的说明,请告诉我。