FatalExecutionEngineError в методе asyn c - PullRequest
0 голосов
/ 01 февраля 2020

Хорошо. Итак, я пошел дальше и переписал большую часть кода, в соответствии со статьями, на которые мне указали.

Это выглядит так:

Progress<string, string> progressIndicator;
public void ShowTEF()
{
            progressIndicator = new Progress<(string body, string title)>(AtualizaUI);
            ComunicaComTEF(progressIndicator);
}

private async Task<int> ComunicaComTEF(IProgress<(string body, string title)> progress)
        {
            int retorno = 10000;
            return await Task.Run<int>(() =>
            {
                while (retorno == 10000)
                {
                    if (estadoTEF != StateTEF.OperacaoPadrao && estadoTEF != StateTEF.RetornaMenuAnterior)
                    {
                        Debug.WriteLine("estadoTEF != OperacaoPadrao. Awaiting response");
                        return 0;
                    }
                    else
                    {
                        Debug.WriteLine("estadoTEF == OperacaoPadrao");
                        retorno = ContinuaVendaTEF();
                    }
                    if (progress != null)
                        progress.Report((mensagemJanela, tituloJanela));
                }
                if (retorno < 0) this.Dispatcher.Invoke(() => DialogBox.Show("ERRO DE TEF", DialogBox.DialogBoxButtons.No, DialogBox.DialogBoxIcons.Error, true, "Erro!"));
                if (statusAtual != StatusTEF.Confirmado) statusAtual = StatusTEF.Erro;
                Debug.WriteLine("Closing window due to loop ending");
                this.Dispatcher.Invoke(() => this.Close());
                StatusChanged?.Invoke(this, new TEFEventArgs() { TipoDoTEF = _tipoTEF, Valor = valor, idMetodo = _idMetodo, status = statusAtual });
                return 0;
            });
        }

        private int ContinuaVendaTEF()
        {
            Debug.WriteLine(Encoding.ASCII.GetString(bufferTEF).Split('\0')[0], 0);
            var retorno = ContinuaFuncaoSiTefInterativo(ref Comando, ref TipoCampo, ref TamMinimo, ref TamMaximo, bufferTEF, bufferTEF.Length, 0);
            ProcessaComando(Comando, bufferTEF);
            LimpaBuffer();
            return retorno;
        }

ProcessaComando - это переключатель, который, в зависимости от того, comando что-то делает, например, выводит сообщение

private void ExibeMensagemOperador(byte[] buffer)
{
    tituloJanela = "OPERAÇÃO NO TEF";
    mensagemJanela = Encoding.ASCII.GetString(buffer).Split('\0')[0];
}

или просит пользователя нажать любую клавишу

public void PerguntaSimOuNao(byte[] pergunta)
{
    estadoTEF = StateTEF.AguardaSimNao;
    mensagemJanela = "(S)im / (N)ão";
    tituloJanela = Encoding.ASCII.GetString(pergunta).Split('\0')[0];
}

, которая затем захватывается PreviewTextInput

private void Window_PreviewTextInput(object sender, TextCompositionEventArgs e)
        if (estadoTEF == StateTEF.AguardaSimNao && (e.Text.ToUpper() == "S" || e.Text.ToUpper() == "N"))
        {
            LimpaBuffer();
            if (e.Text.ToUpper() == "S")
            {
                bufferTEF = Encoding.ASCII.GetBytes("0");
                estadoTEF = StateTEF.OperacaoPadrao;
                ComunicaComTEF(progressIndicator);
            }
            else if (e.Text.ToUpper() == "N")
            {
                bufferTEF = Encoding.ASCII.GetBytes("1");
                estadoTEF = StateTEF.OperacaoPadrao;
                ComunicaComTEF(progressIndicator);
            }
        }

Теперь для новой информации. Когда я запускаю его с помощью Task, без NO async / await, просто возвращаю Task и его результат синхронно вызывает FatalExecutionError. Если от ComunicaComTef до int и удалить Task.Run (просто синхронный запуск кода), ошибка не сработает, а l oop работает без нареканий.


Предыдущая версия вопроса , при необходимости:

Последние несколько месяцев я изучал асинхронное c программирование и обнаружил ошибку, не знаю, как отлаживать / обрабатывать:

Вот настройки. У меня есть окно ShowTEF, которое вызывает два метода, IniciaFuncaoSitef и async ComunicaComTEF. Оба они вызывают внешние методы dll, которые возвращают целочисленные значения, и byte [] по ссылке.

IniciaFuncaoSitef просто запускает операцию, предоставляя некоторые параметры для внешней библиотеки dll. ComunicaComTEF имеет while l oop, который для каждого syn c вызова внешнего метода вызывает this.Dispatcher.Invoke() для обновления sh пользовательского интерфейса. Вот упрощенный код:

    private void AtualizaUI((string body, string titulo) item)
    {
        string a = item.body.TrimEnd('\0');
        string b = item.titulo.TrimEnd('\0');
        tbl_Body.Text = a;
        lbl_Title.Text = b;
    } ```

И снова я вызвал предыдущий FatalExecutionError. Вот следующий стэк:

AmbiPDV.exe! PDV_WPF.Telas.SiTEFBox.AtualizaUI (System.ValueTuple item = {System.ValueTuple}) Строка 536 + 0x c байт C# mscorlib. dll! System.Progress> .InvokeHandlers (состояние объекта) + 0x5e байт
WindowsBase.dll! System. Windows .Threading.ExceptionWrapper.InternalRealCall (System.Delegate обратный вызов, аргументы объекта, int numArgs) + 0xae байт
WindowsBase.dll! System. Windows .Threading.ExceptionWrapper.TryCatchWhen (источник объекта = {System. Windows .Threading.Dispatcher}, обратный вызов System.Delegate, аргументы объекта, int numArgs, System.Delegate catchHandler = null) + 0x35 байт
WindowsBase.dll! Система. Windows .Threading.DispatcherOperation.InvokeImpl () + 0xdd байт WindowsBase.dll! Система. Windows .Threading.DispatcherOperation.InvokeInSecurityContext (состояние объекта) + 0x3f байт
WindowsBase.dll! MS.Internal.CulturePreservingExecutionContext.CallbackWrapper (объект obj) + 0x42 байта
mscorlib.dll! System.Threading.ExecutionContext.RunInternal (Syste) m.Threading.ExecutionContext executeContext, System.Threading.ContextCallback обратный вызов, состояние объекта, bool preserveSyncCtx) + 0xc4 байта
mscorlib.dll! обратный вызов, состояние объекта, bool preserveSyncCtx) + 0x17 байт
mscorlib.dll! System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executeContext, обратный вызов System.Threading.ContextCallback, состояние объекта) + 0x44 байт
Windows .dll! MS.Internal. .DispatcherOperation.Invoke () + 0x50 байт WindowsBase.dll! System. Windows .Threading.Dispatcher.ProcessQueue () + 0x176 байт
WindowsBase.dll! System. Windows .Threading.Dispatcher.WndPro cHook (System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool обрабатывается) + 0x5 c байт
WindowsBase.dll! MS.Win32.HwndWrapper.WndPro c (система. IntPtr hwnd = 4458568, int msg = 49656, System.IntPtr wParam = 0, System.IntPtr lParam = 0, ref bool handled = false) + 0xa1 байт
WindowsBase.dll! MS.Win32.HwndSubclass. DispatcherCallbackOperation (объект o) + 0x6 c байтов
WindowsBase.dll! System. Windows .Threading.ExceptionWrapper.InternalRealCall (обратный вызов System.Delegate, аргументы объекта, int numArgs) + 0x52 байта
WindowsBase.dll ! System. Windows .Threading.ExceptionWrapper.TryCatchWhen (источник объекта = {System. Windows .Threading.Dispatcher}, обратный вызов System.Delegate, аргументы объекта, int numArgs, System.Delegate catchHandler = null) + 0x35 байт
WindowsBase.dll! System. Windows .Threading.Dispatcher.LegacyInvokeImpl (System. Windows .Threading.DispatcherPriority priority, System.TimeSpan timeout, метод System.Delegate, объектные аргументы, int numArgs) + 0x142 байт
WindowsBase.dll! MS.Win32.HwndSubclass.SubclassWndPro c (System. ] [Управляемый в собственный переход]
WindowsBase.dll! System. Windows .Threading.Dispatcher.PushFrameImpl (System. Windows .Threading.DispatcherFrame f rame = {System. Windows .Threading.DispatcherFrame}) + 0xbb bytes
WindowsBase.dll! System. Windows .Threading.Dispatcher.PushFrame (System. Windows .Threading.DispatcherFrame frame) + 0x4d байт
PresentationFramework.dll! System. Windows .Application.RunDispatcher (объект игнорируется) + 0x60 байт
PresentationFramework.dll! System. Windows .Application.RunInternal (System. Windows .Window) + 0x7a байт
PresentationFramework.dll! System. Windows .Application.Run (System. Windows .Window окно) + 0x2e байт
PresentationFramework.dll! System. Windows .Application.Run () + 0x1e байт AmbiPDV.exe! PDV_WPF.App.Main () + 0x5a байт

Кстати, я хотел бы поблагодарить вас за указание на эту статью о IProgress. Это имеет гораздо больше смысла, чем множество ожидающих и асинхронных пустот!

1 Ответ

0 голосов
/ 10 февраля 2020

На самом деле проблема была не связана с асинхронным программированием, а из-за неуправляемого кода и обработки памяти. Благодаря Alois, который указал мне правильное направление, мне удалось найти, что было не так.

Для внешней библиотеки требуется массив байтов фиксированного размера (22 000 байтов, если быть точным), и он должен находиться на тот же адрес, в то время как библиотека и мое программное обеспечение взаимодействуют. Были сделаны две большие ошибки. Во-первых, каждый раз, когда мне нужно было очистить буфер, чтобы я мог отправлять информацию во внешнюю библиотеку, я использовал bufferTEF = new buffer[22000]. Таким образом, вместо того, чтобы очистить его, я установил новый, следовательно, изменил его адрес, поэтому во внешней библиотеке возникли проблемы с его повторным поиском. Во-вторых, всякий раз, когда я отправлял данные во внешнюю библиотеку, я использовал bufferTEF = Encoding.ASCII.GetBytes("information")), что означает, что я отправил обратно массив той же длины, что и отправленная информация. Поскольку внешняя библиотека ожидала минимум 20000 байт, она взорвалась и не знала, что делать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...