TaskScheduler.FromCurrentSynchronizationContext () in .NET.

I get a run-time exception trying to execute the example below.

Unhandled Exception: System.InvalidOperationException: The current SynchronizationContext may not be used as a TaskScheduler. at System.Threading.Tasks.SynchronizationContextTaskScheduler..ctor() at System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext() at TaskDemo.MyForm..ctor() in D:\myStudio\ASPNet\CSharp\CSharp4\MyApp\MyApp\Hello.cs:line 428 at TaskDemo.SynchronizationContextTaskScheduler() in D:\myStudio\ASPNet\CSharp\CSharp4\MyApp\MyApp\Hello.cs:line 396 at TaskDemo.Go() in D:\myStudio\ASPNet\CSharp\CSharp4\MyApp\CLRviaCSharp\Hello.cs:line 214 at ComputeOps.Main() in D:\myStudio\ASPNet\CSharp\CSharp4\MyApp\CLRviaCSharp\Hello.cs:line 23 

Code example:

 public class TaskSchedulerTest { public void Test() { SynchronizationContextTaskScheduler(); } private void SynchronizationContextTaskScheduler() { var f = new MyForm(); System.Windows.Forms.Application.Run(); } private sealed class MyForm : System.Windows.Forms.Form { public MyForm() { Text = "Synchronization Context Task Scheduler Demo"; Visible = true; Width = 400; Height = 100; } private readonly TaskScheduler m_syncContextTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); private CancellationTokenSource m_cts; protected override void OnMouseClick(System.Windows.Forms.MouseEventArgs e) { if (m_cts != null) { // An operation is in flight, cancel it m_cts.Cancel(); m_cts = null; } else { // An operation is not in flight, start it Text = "Operation running"; m_cts = new CancellationTokenSource(); // This task uses the default task scheduler and executes on a thread pool thread var t = new Task<Int32>(() => Sum(m_cts.Token, 20000), m_cts.Token); t.Start(); // These tasks use the synchronization context task scheduler and execute on the GUI thread t.ContinueWith(task => Text = "Result: " + task.Result, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, m_syncContextTaskScheduler); t.ContinueWith(task => Text = "Operation canceled", CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, m_syncContextTaskScheduler); t.ContinueWith(task => Text = "Operation faulted", CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, m_syncContextTaskScheduler); } base.OnMouseClick(e); } } } 

Any idea?

+6
source share
2 answers

put the m_syncContextTaskScheduler creation in the form constructor.

 public MyForm() { Text = "Synchronization Context Task Scheduler Demo"; Visible = true; Width = 400; Height = 100; m_syncContextTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); } 
+7
source

Thanks! It works, what is the reason for this?

Because the constructor initializes readonly members that have an initializer too early. The constructor of the Form class, if necessary, sets up the synchronization provider, an instance of the class named WindowsFormsSynchronizationContext. The C # compiler generates read-only code for initializers before calling the base class constructor. Moving the assignment to the constructor body ensures that it is initialized after the base constructor is called.

Be careful with readonly member initializers, keep them simple.

+6
source

Source: https://habr.com/ru/post/901878/


All Articles