Задача не всегда возвращается после завершения - PullRequest
0 голосов
/ 13 декабря 2018

Итак, я пытаюсь создать программу для управления машиной.Связь с указанной машиной осуществляется через последовательный порт, для которого я написал драйвер.Непрерывный опрос устройства необходим для обратной связи о состоянии и т. Д. В моей программе у меня есть выделенный класс 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 относительно того, обнаруживается ли проблема.Я почти уверен, что моя проблема связана с многопоточностью, но точно не знаю, что происходит не так.Буду очень признателен за любую помощь в правильном направлении!

...