Run different task in same asynchronous thread in C# [duplicate]

痴心易碎 提交于 2021-01-28 22:03:41

问题


I had to ask since I cannot found the same way as UI BeginInvoke asynchronous done.

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 BeginInvoke.

Log from Winforms UI:

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

I want to convert it to class library to integrate as DLL for my real application. But I cannot found how do I make fnCmdInProgressAction and SendNextCommand 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.

Log from my class library:

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

I have tried ThreadPool, Delegate.BeginInvoke, Thread Task. But still result in different thread. Below are sample of what I have tried:

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(() => { fnCmdInProgressAction(state, cr); }).Start();
    //=========================  TRY 2   =================================================
    CmdInProgressAction fn = fnCmdInProgressAction;
    fn.BeginInvoke(state, cr, null, null);
    //=========================  TRY 3   =================================================
    new Thread(new ThreadStart(() => fnCmdInProgressAction(state, cr))).Start();
    //=========================  TRY 4   =================================================
    ThreadPool.QueueUserWorkItem(fnCmdInProgressAction, new object[] { state, cr });
}
public void SendNextCommand(TXNextCommand tnxc)
{
    Thread thread = Thread.CurrentThread;
    string message = $"[SendNextCommand] Background: {thread.IsBackground}, Thread Pool: {thread.IsThreadPoolThread}, Thread ID: {thread.ManagedThreadId}";
    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($"Read Cassette {nextChannel} Deno", "RV-1X2", 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);
}

What is the correct way to run the delegate from HandleReply and fnCmdInProgressAction in the same thread so on SendNextCommand calling, the m_CmdInProgress 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.


回答1:


Answering my question. With recommendation from Peter Csala I'm using using ConcurrentExclusiveSchedulerPair. Now the command can execute as desired. Here what I've done.

static ConcurrentExclusiveSchedulerPair taskSchedulerPair = new ConcurrentExclusiveSchedulerPair();
TaskFactory exclusiveTaskFactory = new TaskFactory(taskSchedulerPair.ExclusiveScheduler);

private void SetCmdInProgress(bool state, Tools.CommandReply cr)
{
    //====================================================================================
    exclusiveTaskFactory.StartNew(() => { fnCmdInProgressAction(new object[] { state, cr }); });
    //====================================================================================
}
private string HandleReply(bool GoodResult, Tools.CommandReply cr)
{
    int nextChannel = cr.m_tag + 1;
    TXCommand.TXNextCommand tnxc = new TXCommand.TXNextCommand(new TXCommand.TXReadCassetteDeno($"Read Cassette {nextChannel} Deno", "RD/9X27", 5, channel: nextChannel));
    tnxc.mcr.SetReplyHandlerDelegate(HandleReply);
    //====================================================================================
    exclusiveTaskFactory.StartNew(() => { SendNextCommand(new object[] { tnxc }); });
    //====================================================================================
}

I still got some of different thread id; though, by using ConcurrentExclusiveSchedulerPair, it can queue the task before proceed with another task as the flow desired



来源:https://stackoverflow.com/questions/65695689/run-different-task-in-same-asynchronous-thread-in-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!