我感兴趣的是为什么我们需要调用 InvokeOnMainThread 而这将是 TaskScheduler.FromCurrentSynchronizationContext() 的主要意图和责任?
我在 Monotouch 中为 iPhone 应用程序使用 TPL 来执行一些后台任务并通过记者类更新 UI。但似乎 TaskScheduler.FromCurrentSynchronizationContext() 没有像您期望的那样与 UI 线程同步。此时,我设法通过使用 InvokeOnMainThread 使其工作(但仍然感觉不对),如Xamarin 网站上的线程主题所述。
我还在 BugZilla 上发现了一个报告的(类似)错误,似乎已经解决了。还有另一个关于在 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 中进行了报告!!!
进展:我还没有弄清楚这个..有人吗?