내가 관심을 가지고있는 것은 InvokeOnMainThread를 호출해야하는 이유입니다. TaskScheduler.FromCurrentSynchronizationContext()?의 주요 의도와 책임은 무엇입니까?TaskScheduler.FromCurrentSynchronizationContext가 Monotouch에서 동기화되지 않는 이유는 무엇입니까?
저는 iPhone 앱을위한 Monotouch에서 TPL을 사용하여 백그라운드 작업을 수행하고 리포터 클래스를 통해 UI를 업데이트합니다. 하지만 TaskScheduler.FromCurrentSynchronizationContext()는 예상대로 UI 스레드와 동기화되지 않는 것으로 보입니다. 지금은 Xamarin 사이트의 Threading 주제에 설명 된대로 InvokeOnMainThread를 사용하여 문제를 해결할 수있었습니다.
또한 BugZilla에서보고 된 (유사한) bug이 해결 된 것으로 확인되었고 Monochay에 백그라운드 스레드를 사용하는 기본 방법에 대해 다른 threading question이 발견되었습니다.
다음은 내 질문을 설명하고 동작을 보여주는 코드 단편입니다.
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에서보고를 수행한다는 것입니다.
진행 : 아직이 문제를 파악하지 못했습니다. 누구입니까?
감사합니다 Sandor하지만이 시도하고 작동하지 않았다. 콘솔 결과와 동일한 결과를 제공하며 UI에 진행 상황이 표시되지 않습니다. 내 질문에 언급 한 바와 같이 'ContinueWith()'InvokeOnMainThread() '호출 할 필요없이 작동하는 것 같습니다. –
WinForms 프로젝트를 사용하여 Windows에서만이 작업을 시도했음을 인정해야합니다. Windows에서 콘솔 프로젝트는'TaskScheduler.FromCurrentSynchronizationContext()'를 허용하지 않습니다. 예외가 발생합니다 : '현재 SynchronizationContext는 TaskScheduler로 사용할 수 없습니다.' –
@RemcoKoedoot,이 기술을 사용하는 업데이트 된 코드를 질문에 편집하여 보여줄 수 있습니까? –