微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 C# 中的同一个异步线程中运行不同的任务

如何解决在 C# 中的同一个异步线程中运行不同的任务

我不得不问,因为我找不到与 UI BeginInvoke 异步完成相同的方式。

我在 Winforms 上运行的示例程序和所有委托方法都在主 UI 线程中调用。我记录了状态,发现它在不同的 BeginInvoke 上的同一线程上运行。

从 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 ID: 1
13/01/2021 11:57:23 [SendNextCommand] - [SendNextCommand] Background: False,Thread ID: 1
13/01/2021 11:57:24 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: False,Thread ID: 1
13/01/2021 11:57:24 [SendNextCommand] - [SendNextCommand] Background: False,Thread ID: 1

我想将其转换为类库,以便为我的实际应用程序集成为 DLL。但是我找不到如何让 fnCmdInProgressActionSendNextCommand 方法在同一个线程中运行。因为,我有一个链式命令,它需要排队,因为对象值将被清除并允许下一个命令执行到串口。

从我的类库登录

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 ID: 9
13/01/2021 11:30:55 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: True,Thread ID: 7
13/01/2021 11:30:55 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: True,Thread ID: 6
13/01/2021 11:30:56 [SendNextCommand] - [SendNextCommand] Background: True,Thread ID: 7
13/01/2021 11:30:56 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: True,Thread ID: 9
13/01/2021 11:30:57 [fnCmdInProgressAction] - [fnCmdInProgressAction] Background: True,Thread ID: 7
13/01/2021 11:30:58 [SendNextCommand] - [SendNextCommand] Background: True,Thread ID: 6

我尝试过 ThreadPool、Delegate.BeginInvoke、Thread Task。但仍然导致不同的线程。以下是我尝试过的示例:

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);
}

在同一线程中从 HandleReplyfnCmdInProgressAction 运行委托的正确方法是什么,例如 SendNextCommand 调用m_CmdInProgress 已经为空,因此它可以发送下一个命令。 Winforms UI 没有问题,因为它就像在同一线程上排队调用。我如何将它应用于类库,因为我尝试过的无法实现我想要的。我已经阅读了任务异步编程,TPL。我不能使用异步,因为它会弄乱串行类对象上的委托。

解决方法

回答我的问题。根据 Peter Csala 的推荐,我正在使用 ConcurrentExclusiveSchedulerPair。现在命令可以根据需要执行。这是我所做的。

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 }); });
    //====================================================================================
}

我仍然得到了一些不同的线程 id;但是,通过使用 ConcurrentExclusiveSchedulerPair,它可以将任务排入队列,然后根据需要的流程继续执行另一个任务

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。