делегировать.Вызов и делегирование.BeginInvoke — используются в одном и том же методе, возвращают два разных результата

#c# #asynchronous #delegates #timer

#c# #асинхронный #делегаты #таймер

Вопрос:

Я пишу программное обеспечение, которое взаимодействует с 4 устройствами через последовательный порт. Один из них, модуль ввода / вывода (ICP CON), имеет 4 входных канала (DL) и 4 выходных канала (RL). Мне нужно отслеживать состояние каналов DL, а затем, когда обнаруживается сигнал, я должен выполнить некоторую обработку, которая зависит от того, какой сигнал был обнаружен.

Я вызываю 4 метода асинхронно, каждые 500 мс (таймер), вот событие tick:

 //stop the timer
timer1.Stop();

//open com port 2
Tester.Devices.ICP.OpenICPPort(2, 9600);

//dl 0
ic = new CheckDLStatus(0, this);
ic.Execute();

//dl 1
ic = new CheckDLStatus(1, this);
ic.Execute();

//dl 2
ic = new CheckDLStatus(2, this);
ic.Execute();

//dl3 
ic = new CheckDLStatus(3, this);
ic.Execute();

//close com port 2
Tester.Devices.ICP.CloseICPPort(2);

//enable the timer again
timer1.Enabled = true;

public CheckDLStatus(int DL, Form1 F1)
{
    //form 1 instance
    f1 = F1;

    // setup the delegate to call
    switch (DL)
    {
        case (0):
        {
            checkDL_delegate = new checkDL(
                BusinessLogicLayer.Classes.
                DevicesCommunication.CheckDl0);

            break;
        }
        case (1):
        {
            checkDL_delegate = new checkDL(
                BusinessLogicLayer.Classes.
                DevicesCommunication.CheckDl1);

                break;
        }
        case (2):
        {
            checkDL_delegate = new checkDL(
                BusinessLogicLayer.Classes.
                DevicesCommunication.CheckDl2);

                break;
        }
        case (3):
        {
            checkDL_delegate = new checkDL(
                BusinessLogicLayer.Classes.
                DevicesCommunication.CheckDl3);

                break;
        }
    }
}


public static void CheckDl2()
{
    //declare
    bool currentStatus;

    try
    {
        //input
        currentStatus = DevicesCommunication.Dl_2_On; 
        //should be false at the start of the test, 
        //so when it becomes true, the change is detected immediately

        //dl2?
        if (ICP.LookForSignal_DL2((short)2, 
            Util.Classes.Util.ResolveComPortNumber(
                Cache.settings.icpModulePort),     
            Convert.ToInt32(Cache.settings.icpModuleBaudRate)))
        {
            //signal detected
            DevicesCommunication.Dl_2_On = true;
        }
        else
        {
            //signal not detected
            DevicesCommunication.Dl_2_On = false;
        }

        //check, if status of DL2 has been changed 
        //(from true to false, from false to true)
        if (currentStatus != DevicesCommunication.Dl_2_On)
        {
            //status from before checking signal is different
            // from status read from the device so
            //status has changed

            if (DevicesCommunication.Dl_2_On)
            {
                DevicesCommunication.DL2_apperancesCounter  = 1;

                //TODO
                //process
                //ProcessDL2();
            }
        }
        else
        {
            //status did not change
            //just clear buffer
            ClearBuffer();
        }

        return;
    }
    catch (Exception ex)
    {
        Util.Classes.ErrorLogging.LogError(ex, true);
        //EndCurrentTest(); 
        return;
    }
}
  

Execute() метод, который вызывает делегат:

 public void Execute()
{
    // call the method on the thread pool
    checkDL_delegate.BeginInvoke(
        this.CallBack, null);

    //checkDL_delegate.Invoke();
}
  

Метод, который вызывается для проверки состояния DL2:

 public static bool LookForSignal_DL2(short DL_number, int port, int baudRate)
{
    //declare
    bool iBit;

    try
    {
        //check if there is a signal at specified Dl_number
        iBit = DCON.Read_DI_Bit(Convert.ToByte(port), 1, -1, 
            DL_number, 16, 0, 100);

        //return resposne
        return iBit; //true/false
    }
    catch (Exception ex)
    {
        Util.Classes.ErrorLogging.LogError(ex, true);
        return false;
    }
}
  

Моя проблема в том, что когда я включаю сигнал на канале DL2, и я вызываю LookForSignal_DL2 так, без таймера и асинхронных вызовов (только для теста):

 private void button25_Click(object sender, EventArgs e)
{
    ICP.OpenICPPort(2, 9600);

    if (ICP.LookForSignal_DL2(2, 2, 9600))
    {
        MessageBox.Show("True");
    }
    else
    {
        MessageBox.Show("false!");
    }

    ICP.CloseICPPort(2);
}
  

Это работает — возвращает true .

Если в Execute() методе, который я использую Invoke , который делает вызов метода синхронным — он работает (возвращает true), но таким образом я могу проверять только 1 сигнал одновременно.

Если в Execute() методе, который я использую BeginInvoke , он не работает, он возвращает false, даже если в DL2 есть сигнал.

Я признаю, что не знаю, что происходит. У вас есть какие-нибудь идеи?

Комментарии:

1. Что такое this.Callback ?

2. обратный вызов private void(IAsyncResult ar) { checkDL_delegate. EndInvoke(ar); updateStatus_delegate = новый статус обновления(f1.UpdateDLStatus); if (f1.InvokeRequired) { f1.Invoke(updateStatus_delegate); } else { f1.UpdateDLStatus(); } }

3. И что делает CheckDLStatus метод? Было бы действительно полезно, если бы вы могли обновить свой вопрос, включив в него весь вызываемый вами код.

4. BeginInvoke() возвращается немедленно и не блокируется, это означает, что он не ждет сигнала DL2, а LookForSignal_DL2 возвращает false . Скажите мне, если я ошибаюсь.

5. Когда он возвращает false в асинхронном режиме .. есть ли ошибка, записанная в вашем журнале? Я заметил, что вы возвращаете false при ошибке .. может быть, выбрасываете исключение, пока не отследите его? Я признаю, что прошло несколько лет с тех пор, как я занимался последовательным портом, и это было в .net 2 … но что я помню, так это открытие порта, а затем ожидание запуска события, сообщающего мне, что поступил сигнал. Ваш метод опроса порта кажется мне немного странным.. но тогда я не знаю ваших системных требований… просто подумал, что стоит упомянуть об этом на случай, если вы выберете сложный маршрут, чтобы сделать что-то простое (как я часто делаю :))

Ответ №1:

Я понял это, если это кому-нибудь поможет, я допустил ошибку здесь (жирный текст):

 //stop the timer
timer1.Stop();

//open com port 2
Tester.Devices.ICP.OpenICPPort(2, 9600);

//dl 0
ic = new CheckDLStatus(0, this);
ic.Execute();

//dl 1
ic = new CheckDLStatus(1, this);
ic.Execute();

//dl 2
ic = new CheckDLStatus(2, this);
ic.Execute();

//dl3 
ic = new CheckDLStatus(3, this);
ic.Execute();
  

Тестер.Devices.ICP.CloseICPPort(2);

Я запускал свои методы асинхронно, но выполнение кода продолжалось, и каждый раз порт закрывался до того, как какой-либо из методов мог проверить наличие сигнала. К сожалению, библиотека SDK в этом случае не возвращает никаких ошибок, поэтому она просто продолжала возвращать false .

Спасибо за ваши комментарии.