title: Changing SynchronizationContext Within Async Method
body: <p>I am trying to post a lean question here, without code, because my question is so specific: Is it possible/acceptable to modify the <strong>SynchronizationContext</strong> within an Async method? If I don't set <strong>SynchronizationContext</strong> when the Async method begins, it seems that code within it--including events I raise and methods within the same class module I call--run on the same worker thread. However, when it comes time to interact with the UI, I find that the <strong>SynchronizationContext</strong> has to be set to the UI thread. </p>
  
  <p>Is it okay to keep the <strong>SynchronizationContext</strong> set to the worker thread until such time that I want to invoke a call to a UI-based function?</p>
  
  <p>EDIT:
  To further clarify my above question, I find myself in a no-win situation with respect to the SynchronizationContext setting. If don't set the SynchronizationContext then my async operations run on a separate thread (as desired) but then I can't return data to the UI thread without encountering a cross-thread operation exception; if I set the SynchronizationContext to my UI thread then the operations I want to run on a separate thread end up running on the UI thread--and then (of course) I avoid the cross-thread exception and everything works. Clearly, I'm missing something. </p>
  
  <p>If you care to read more, I've tried to provide a very clear explanation of what I'm trying to do and I realize you're investing your time to understand so thank you for that!</p>
  
  <p>What I'm trying to do is shown in this flow diagram:</p>
  
  <p><a href="https://i.stack.imgur.com/Yhb6k.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Yhb6k.png" alt="enter image description here"></a></p>
  
  <p>I have a Winforms application running on the UI thread (in black); I have a Socket object I'd like to run on its own thread. The job of the socket class is to read data from a communication socket and raise events back to the UI whenever data arrives. </p>
  
  <p>Note that I start a message loop from the UI thread so that the socket is continually polled for data on its own thread; if data is received, I want to process that data synchronously on the same non-UI thread before grabbing any more data from the socket. (Yes, if something goes awry with any particular socket read, the socket might be left with unread data in it.)</p>
  
  <p>The code to start the message loop looks like this:</p>
  
  <pre><code>if (Socket.IsConnected)
  {
     SetUpEventListeners();
     // IMPORTANT: next line seems to be required in order to avoid a cross-thread error
     SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
     Socket.StartMessageLoopAsync();
  }
  </code></pre>
  
  <p>When I start the message loop from the UI thread, I call an async method on the <code>Socket</code> object:</p>
  
  <pre><code> public async void StartMessageLoopAsync()
    {
       while (true)
       {
          // read socket data asynchronously and populate the global DataBuffer
          await ReadDataAsync();
  
          if (DataBuffer.Count == 0)
          {
             OnDataReceived();
          }
       }
    }
  </code></pre>
  
  <p>The <code>Socket</code> object also has the <code>OnDataReceived()</code> method defined as:</p>
  
  <pre><code>  protected void OnDataReceived()
    {
       var dataEventArgs = new DataEventArgs();
       dataEventArgs.DataBuffer = DataBuffer;
  
       // *** cross-thread risk here!
       DataReceived?.Invoke(this, dataEventArgs);
    }
  </code></pre>
  
  <p>I have highlighted two areas of the diagram with "1" and "2" blue stars. </p>
  
  <p>In "1" (on the diagram), I am using the async/await pattern. I am using a third-party socket tool that doesn't support Async, so I have wrapped that in my own <code>ReadDataAsync()</code> function that looks like this:</p>
  
  <pre><code>  public override async Task ReadDataAsync()
    {
       // read a data asynchronously
       var task = Task.Run(() =&gt; ReadData());
       await task;
    }
  </code></pre>
  
  <p><code>ReadData()</code> wraps the third-party component's read method: it populates a global data buffer, so no return value is needed.</p>
  
  <p>In "2" in the diagram, I am encountering the cross-thread risk described in my <code>OnDataReceived()</code> method cited above.</p>
  
  <p>Bottom Line: If I set <code>SynchronizationContext</code> as shown in my first code clip above, then everything in the Socket object runs on its own thread until I try to invoke the DataReceived event handler; if I comment-out the <code>SynchronizationContext</code> then the only part of the code that runs on its own thread is the brief third-party socket-read operation wrapped in my <code>DataReadAsync()</code> method. </p>
  
  <p>So my thought was whether I can set the <code>SynchronizationContext</code> just ahead of trying to invoke the DataReceived event handler. And even if I "can", the better question is whether this is a good idea. If I do modify <code>SynchronizationContext</code> within the non-UI thread then I'd have to set it back to its original value after invoking the DataReceived method, and that has a Durian-like code-smell to me. </p>
  
  <p>Is there an elegant tweak to my design or does it need an overhaul? My goal is to have all red items in the diagram running on a non-UI thread and the black items running on the UI thread. "2" is the point at which the non-UI thread my cross over to the UI thread... </p>
  
  <p>Thank you.  </p>