gpt4 book ai didi

c# - 为什么 TaskScheduler.FromCurrentSynchronizationContext 在 Monotouch 中不同步?

转载 作者:太空宇宙 更新时间:2023-11-03 14:04:35 26 4
gpt4 key购买 nike

我感兴趣的是为什么我们需要调用 InvokeOnMainThread 而这将是 TaskScheduler.FromCurrentSynchronizationContext() 的主要意图和职责?

我在 iPhone 应用程序的 Monotouch 中使用 TPL 来执行一些后台任务并通过记者类更新 UI。但似乎 TaskScheduler.FromCurrentSynchronizationContext() 没有像您期望的那样同步到 UI 线程。此时我设法通过使用 InvokeOnMainThread 使其工作(但仍然感觉不对),如 Threading 所述Xamarin 网站上的主题。

我还发现了一个报告(类似)bug在 BugZilla,这似乎已经解决了……还有另一个 threading question关于在 MonoTouch 中使用后台线程的首选方式。

下面是用于说明我的问题并展示行为的代码片段。

    private CancellationTokenSource cancellationTokenSource;

private void StartBackgroundTask ()
{
this.cancellationTokenSource = new CancellationTokenSource ();
var cancellationToken = this.cancellationTokenSource.Token;
var progressReporter = new ProgressReporter ();

int n = 100;
var uiThreadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine ("Start in thread " + uiThreadId);

var task = Task.Factory.StartNew (() =>
{
for (int i = 0; i != n; ++i) {

Console.WriteLine ("Work in thread " + Thread.CurrentThread.ManagedThreadId);

Thread.Sleep (30);

progressReporter.ReportProgress (() =>
{
Console.WriteLine ("Reporting in thread {0} (should be {1})",
Thread.CurrentThread.ManagedThreadId,
uiThreadId);

this.progressBar.Progress = (float)(i + 1) / n;
this.progressLabel.Text = this.progressBar.Progress.ToString();

});
}

return 42; // Just a mock result
}, cancellationToken);

progressReporter.RegisterContinuation (task, () =>
{
Console.WriteLine ("Result in thread {0} (should be {1})",
Thread.CurrentThread.ManagedThreadId,
uiThreadId);

this.progressBar.Progress = (float)1;
this.progressLabel.Text = string.Empty;

Util.DisplayMessage ("Result","Background task result: " + task.Result);

});
}

记者类有这些方法

    public void ReportProgress(Action action)
{
this.ReportProgressAsync(action).Wait();
}
public Task ReportProgressAsync(Action action)
{
return Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}
public Task RegisterContinuation(Task task, Action action)
{
return task.ContinueWith(() => action(), CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}
public Task RegisterContinuation<TResult>(Task<TResult> task, Action action)
{
return task.ContinueWith(() => action(), CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}

应用程序输出窗口中的结果将是:

Start in thread 1
Work in thread 6
Reporting in thread 6 (should be 1)
Work in thread 6
Reporting in thread 6 (should be 1)
...
Result in thread 1 (should be 1)

如您所见,“在线程 6 中工作”很好。报告也在线程 6 上,这是错误的。有趣的是 RegisterContinuation 在线程 1 中进行报告!!!


进展:我还没有想出这个……有人吗?

最佳答案

我认为问题在于您通过执行 TaskScheduler.FromCurrentSynchronizationContext() 从 ProgressReporter 类中检索任务调度程序。

您应该将任务调度器传递给 ProgressReporter 并改用它:

public class ProgressReporter
{
private readonly TaskScheduler taskScheduler;

public ProgressReporter(TaskScheduler taskScheduler)
{
this.taskScheduler = taskScheduler;
}

public Task RegisterContinuation(Task task, Action action)
{
return task.ContinueWith(n => action(), CancellationToken.None,
TaskContinuationOptions.None, taskScheduler);
}

// Remaining members...
}

通过将从 UI 线程获取的任务调度器传递给进度报告器,您可以确定任何报告都是在 UI 线程上完成的:

TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
ProgressReporter progressReporter = new ProgressReporter(uiScheduler);

关于c# - 为什么 TaskScheduler.FromCurrentSynchronizationContext 在 Monotouch 中不同步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9773625/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com