【发布时间】:2012-03-19 16:07:11
【问题描述】:
我感兴趣的是为什么我们需要调用 InvokeOnMainThread 而这将是 TaskScheduler.FromCurrentSynchronizationContext() 的主要意图和责任?。
我在 Monotouch 中为 iPhone 应用程序使用 TPL 来执行一些后台任务并通过报告器类更新 UI。但似乎 TaskScheduler.FromCurrentSynchronizationContext() 没有像您期望的那样与 UI 线程同步。此时,我设法通过使用 InvokeOnMainThread 使其工作(但仍然感觉不对),如 Xamarin 网站上的 Threading 主题所述。
我还在 BugZilla 上发现了一个报告的(类似的)bug,它似乎已经解决了。还有另一个 threading question 关于在 MonoTouch 中使用后台线程的首选方式。
下面是代码 sn-p 来说明我的问题并显示行为。
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 中进行报告!!!
进展:我还没有弄清楚这个..有人吗?
【问题讨论】:
标签: c# multithreading xamarin.ios task-parallel-library synchronizationcontext