C# 由用户启动的多个线程。仅使用上一个的结果

C# 由用户启动的多个线程。仅使用上一个的结果,c#,C#,我有一个应用程序,其中用户提供要由线程处理的数据,然后线程将数据返回到UI中。用户可以从另一个线程开始更改输入。如何正确地忽略旧的重复线程 我注意到有两种解决方案经常被描述。 1) 在调用中,检查当前输入数据是否与处理的线程相同 2) 等待第一个线程结束,然后再启动另一个线程 第一个解决方案是可行的,但若用户再次将输入更改为相同的值,并且我得到两次或更多具有相同数据的刷新UI,则可能会使用更旧的线程 第二个选项响应性较差,特别是当线程中的计算运行时间较长时,因为我们必须等待每个线程完成其工作 我

我有一个应用程序,其中用户提供要由线程处理的数据,然后线程将数据返回到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
           }

  }

如果用户调用了几个线程,并且可以更新其中任何线程中的数据, 我认为您应该添加一个最新更新的属性。
并跟踪用户何时进行更改,并据此比较线程。

您应该使用专门设计的工具来处理此类事情,并且它是Microsoft的反应式框架

您只需编写以下代码:

    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
                });
    }
public主窗口()
{
初始化组件();
IDisposable订阅=
可观察
.FromEventPattern(
h=>Button.MouseLeftButtonDown+=h,
h=>Button.MouseLeftButtonDown-=h)
.Select(x=>Observable.Start(()=>{Update(42);return 42;}))
.Switch()
.ObserveOnDispatcher()
.订阅(x=>
{
//仅限最新结果,在UI中执行一些工作
});
}
这通过调用
Update(42)响应
MouseLeftButtonDown
事件;返回42在后台线程上。然后它调用
.Switch()
,这是一个特殊的操作符,确保只返回对
可观察的最新调用的结果。返回Start(()=>{Update(42);return 42;})
(它忽略以前的任何一个,不管它们是否先出现)。然后,它使用
.ObserveOnDispatcher()
操作符将数据编组回UI。最后,
.Subscribe(x=>
允许UI响应UI线程上的返回值

请记住,问题中的示例代码没有完全充实,所以我对它进行了一些捏造,但我想你明白了

订阅上调用
.Dispose()
会分离事件处理

只需NuGet“System.Reactive.Windows.Threading”来获取位,并使用System.Reactive.Linq;
添加到代码中,以获得所需的扩展方法


如果需要进一步解释,请告诉我。

如果可能,我建议使用带有
CancellationToken
任务
。请注意,取消是合作的。如果此任务在计算上非常昂贵,您确定要给用户创建所需数量的任务的能力吗?一些用户会向您知道的按钮发送垃圾邮件w、 这类似于自动完成功能。用户可以键入许多字母,在提供响应之前,您不会阻止输入下一个字母。而是会应用一些延迟来防止产生太多线程。我不能使用task,因为在我的情况下线程必须是STA。我也有点担心取消令牌可能由于调用而无法工作到主线程。所以我可以检查它的状态的最后一个地方是在调用之前,而调用可能会等待到UI线程,在那个里用户可能会启动一个新线程。
如何正确地忽略旧的重试线程?
向每个请求传递一个
int
值参数。为每个请求递增它。跟踪
int
的最新的响应。忽略任何
响应
,其中
int
在最新响应之前。您可能需要一个
来处理同时出现的两个响应。