title: Run different task in same asynchronous thread in C#
body: <p>I had to ask since I cannot found the same way as UI BeginInvoke asynchronous done.</p>
  <p>My sample program running on Winforms and all the delegate method is calling in the main UI thread. I have log the status and found it run on same thread on different <code>BeginInvoke</code>.</p>
  <p>Log from Winforms UI:</p>
  <pre><code>13/01/2021 11:57:23 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: False, Thread Pool: False, Thread ID: 1
  13/01/2021 11:57:23 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: False, Thread Pool: False, Thread ID: 1
  13/01/2021 11:57:23 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: False, Thread Pool: False, Thread ID: 1
  13/01/2021 11:57:23 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: False, Thread Pool: False, Thread ID: 1
  13/01/2021 11:57:23 [SendNextCommand] - [SendNextCommand] Background: False, Thread Pool: False, Thread ID: 1
  13/01/2021 11:57:23 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: False, Thread Pool: False, Thread ID: 1
  13/01/2021 11:57:24 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: False, Thread Pool: False, Thread ID: 1
  13/01/2021 11:57:24 [SendNextCommand] - [SendNextCommand] Background: False, Thread Pool: False, Thread ID: 1
  13/01/2021 11:57:24 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: False, Thread Pool: False, Thread ID: 1
  13/01/2021 11:57:24 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: False, Thread Pool: False, Thread ID: 1
  13/01/2021 11:57:24 [SendNextCommand] - [SendNextCommand] Background: False, Thread Pool: False, Thread ID: 1
  </code></pre>
  <p>I want to convert it to class library to integrate as DLL for my real application. But I cannot found how do I make <code>fnCmdInProgressAction</code> and <code>SendNextCommand</code> method to run in same thread. Because, I have a chain command and it need to queue as object value will be clear and allow next command to execute to serial port.</p>
  <p>Log from my class library:</p>
  <pre><code>13/01/2021 11:30:51 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: True, Thread Pool: True, Thread ID: 6
  13/01/2021 11:30:52 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: True, Thread Pool: True, Thread ID: 9
  13/01/2021 11:30:55 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: True, Thread Pool: True, Thread ID: 7
  13/01/2021 11:30:55 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: True, Thread Pool: True, Thread ID: 6
  13/01/2021 11:30:56 [SendNextCommand] - [SendNextCommand] Background: True, Thread Pool: True, Thread ID: 7
  13/01/2021 11:30:56 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: True, Thread Pool: True, Thread ID: 9
  13/01/2021 11:30:57 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: True, Thread Pool: True, Thread ID: 7
  13/01/2021 11:30:58 [SendNextCommand] - [SendNextCommand] Background: True, Thread Pool: True, Thread ID: 6
  </code></pre>
  <p>I have tried ThreadPool, Delegate.BeginInvoke, Thread Task. But still result in different thread. Below are sample of what I have tried:</p>
  <pre><code>private delegate void CmdInProgressAction(bool state, Tools.CommandReply cr);
  private void fnCmdInProgressAction(object param)
  {
      if (cr != null)
      {
          m_CmdInProgress = cr;
          //.......
      }
      m_CmdInProgress = null;
  }
  // Code from Winform UI BeginInvoke
  private void SetCmdInProgress(bool state, CommandReply cr)
  {
      CmdInProgressAction fn = null;
      object[] param = new object[] { state, cr };
      fn = new CmdInProgressAction(fnCmdInProgressAction);
      BeginInvoke(fn, param);
  }
  // My try
  private void SetCmdInProgress(bool state, CommandReply cr)
  {
      //=========================  TRY 1   =================================================
      new Task(() =&gt; { fnCmdInProgressAction(state, cr); }).Start();
      //=========================  TRY 2   =================================================
      CmdInProgressAction fn = fnCmdInProgressAction;
      fn.BeginInvoke(state, cr, null, null);
      //=========================  TRY 3   =================================================
      new Thread(new ThreadStart(() =&gt; fnCmdInProgressAction(state, cr))).Start();
      //=========================  TRY 4   =================================================
      ThreadPool.QueueUserWorkItem(fnCmdInProgressAction, new object[] { state, cr });
  }
  public void SendNextCommand(TXNextCommand tnxc)
  {
      Thread thread = Thread.CurrentThread;
      string message = $&quot;[SendNextCommand] Background: {thread.IsBackground}, Thread Pool: {thread.IsThreadPoolThread}, Thread ID: {thread.ManagedThreadId}&quot;;
      WriteLog.ProcessLog(message);
      if (m_CmdInProgress == null)
      {
          m_CmdInProgress = tnxc.mcr;
          serial.SendCommand(m_CmdInProgress);
      }
  }
  private string HandleReply(bool GoodResult, Tools.CommandReply cr)
  {
          int nextChannel = cr.m_tag + 1;
          TXNextCommand tnxc= new TXNextCommand(new TXReadCassetteDeno($&quot;Read Cassette {nextChannel} Deno&quot;, &quot;RV-1X2&quot;, 5, channel: nextChannel));
          tnxc.mcr.SetReplyHandlerDelegate(HandleReply);
          /// Below is code from Winforms UI Async on main thread
          dSendNextCommand fn = new dSendNextCommand(SendNextCommand);
          object[] param = new object[] { nctt };
          BeginInvoke(fn, param);
  }
  </code></pre>
  <p>What is the correct way to run the delegate from <code>HandleReply</code> and <code>fnCmdInProgressAction</code> in the same thread so on <code>SendNextCommand</code> calling, the <code>m_CmdInProgress</code> is already null so it can send next command. The Winforms UI having no problem as it's like queue the invoke on the same thread. How do I apply this on class library since what I have tried cannot achieve what I desired. I have read about Task Asynchronous Programming, TPL. I cannot use async as it will mess the delegate on the serial class object.</p>