任务并非总是在完成后返回

时间:2018-12-13 13:24:57

标签: c# task

所以我试图构建一个程序来控制机器。与上述机器的通讯是通过我为其编写驱动程序的串行端口进行的。对于状态反馈等,必须对机器进行连续轮询。在我的程序中,我有一个专用的ExecutionEngine()类来处理串行发送和接收。我还需要运行两个单独的控制序列,分别将它们放入方法RunSequenceA()RunSequenceB()中。在正常操作期间,所有三种方法都需要运行,直到两个控制序列完成为止,这时将调用StopSequence()方法。我的问题是,有时出于某种原因,永远不会调用StopSequence()方法,而使我的ExecutionEngine()方法陷入无限循环!

ExecutionEngine()的代码:

private static void ExecutionEngine()
{
    // Clear both lists in case they have old data
    _commandList.Clear();
    _pollingList.Clear();

    // Poll while user has not yet clicked "STOP"
    while (!_cTokenSource.Token.IsCancellationRequested)
    {
        // If there are commands to be sent, send them first
        if (_commandList.Count > 0)
        {
            Command[] tempCommandArray;

            lock (_commandList)
                tempCommandArray = _commandList.ToArray();

            foreach (var c in tempCommandArray)
            {
                if (_cTokenSource.Token.IsCancellationRequested)
                    break;

                var response = SerialDriver.ComCycle(c.CommandBytes, _serialPort);
                var success = CheckErrorReturn(response, false);

                if (success)
                {
                    AddPolling(c);
                    RemoveCommand(c);
                }
            }
        }
        // Do polling operation on applicable controllers
        if (_pollingList.Count > 0)
        {
            Command[] tempPollingArray;

            lock (_pollingList)
                tempPollingArray = _pollingList.ToArray();

            foreach (var c in tempPollingArray)
            {
                if (_cTokenSource.Token.IsCancellationRequested)
                    break;

                var response = SerialDriver.ComCycle(c.PollBytes, _serialPort);
                var success = ProcessPollReturn(response);

                if (success)
                {
                    c.FlagDone();
                    RemovePolling(c);
                }
            }
        }

        if (_commandList.Count + _pollingList.Count == 0)
        {
            // Will get stuck here if neither list gets new items added
            Console.WriteLine("Bad place");
            Thread.Sleep(500);
        }
    }

    // Cancellation has been requested
    lock (_commandList)
        _commandList.Clear();

    lock (_pollingList)
        _pollingList.Clear();

    ResetTriggers();

    var endCommand = new Command("GL_SYSCMD", 0);
    SerialDriver.ComCycle(endCommand.CommandBytes, _serialPort);
    _serialPort.Close();
    _vm.SequenceRunning = false;
    return;
}

运行序列的代码:

private static async Task RunSequencesAsync()
{
    var taskArray = new Task[2];

    var a = new Action(RunSequenceA);
    var b = new Action(RunSequenceB);

    taskArray[0] = Task.Run(a);
    taskArray[1] = Task.Run(b);

    await Task.WhenAll(taskArray).ConfigureAwait(continueOnCapturedContext: false);

    // Sometimes this never fires, WHY?
    UpdateStatus("All done!");
    StopSequence();
}

// Run A sequence
internal static void RunSequenceA()
{
    if (_sequenceA1 != null && _sequenceA1.Count > 0)
    {
        foreach (var s in _sequenceA1)
        {
            if (_cTokenSource.Token.IsCancellationRequested)
                return;

            s.Execute();

            if (s.Reference != null && TriggerStepCompleted != null)
                TriggerStepCompleted(s, EventArgs.Empty);
        }

        // This part always fires
        Console.WriteLine("Sequence A finished");
        return;
    }
    else
        return;
}

最后,是启动和停止所有内容的方法:

private static async Task StartSequenceAsync()
{
    _serialPort.PortName = _vm.SelectedComPort;
    _serialPort.Open();
    _serialPort.DiscardInBuffer();
    _serialPort.DiscardOutBuffer();

    // Start
    _cTokenSource = new CancellationTokenSource();
    _vm.SequenceRunning = true;
    var taskArray = new Task[2];

    taskArray[0] = Task.Run(() => ExecutionEngine());
    Thread.Sleep(50);
    taskArray[1] = Task.Run(() => RunSequencesAsync());

    await Task.WhenAll(taskArray).ConfigureAwait(continueOnCapturedContext: false);
}

private static void StopSequence()
{
    _cTokenSource.Cancel();
}

重申一下,问题并非每次都会发生。实际上,大多数情况下,程序运行良好。似乎只有在执行过程中我手动调用StopSequence()方法时才会出现问题。那么问题是否出现是50/50。我很确定我的问题与线程相关,但不确定到底出了什么问题。向我指出正确方向的任何帮助将不胜感激!

0 个答案:

没有答案