Проблема с System.Thread.Timer

Выполняя извлечение данных из socket.ReceiveFromAsync, есть некоторый функционал для проверки пакетов от отправителя до получателя. Существует определенный класс, который хранит статистику и все данные для передачи. После отправки пакета я запускаю таймер, чтобы дождаться ответа, в идеале я получаю ответ и начинаю убивать таймер. Но бывает, что пакет ответа не возвращается до тех пор, пока время, указанное в таймере, я посылаю повтор. Здесь странности не всегда происходят, но часто это так. Я не получил пакет, функция таймера начинает работать, и я посылаю пакет, чтобы повторить таймер на удержании, в этот момент пакет приходит, например, задержанный пакет, и я уничтожаю таймер. но после времени задержки функция начинает работать при посылке повтора, как если бы я не уничтожил таймер. Я начал выводить лог с ID потока, в котором пакеты принимаются и таймер выполняется, и в каком потоке таймер уничтожается, уничтожение и повторная попытка ложного срабатывания выполняется в разных потоках. Как решить эту проблему?

Получить код :

 public void ReceiveAsync()
 {

    SocketAsyncEventArgs recieveArgs = new SocketAsyncEventArgs();
    recieveArgs.SetBuffer(new byte[_data_size], 0, _data_size);
    recieveArgs.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
    recieveArgs.Completed += ProcessRecievedPacket;

    if (!_socket.ReceiveFromAsync(recieveArgs))
        ProcessRecievedPacket(this, recieveArgs);
}


public void ProcessRecievedPacket(object sender, SocketAsyncEventArgs e)
{
    try
    {
        Monitor.Enter(_lock_receive);
        if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
        {
            ReceiveAsync();
 ...
}

Код отправления : Инициализация класса статистики и т.д. потом : record._start_wait_crl(onEventLog); SendData(remoteAddr, data);

internal static void _start_wait_crl(this StatusNodeRecord record, _OnEventLog onEventLog)
{
    try
    {
        record._timer_wait_crl_acp = new Timer((e) =>
        {
            StatusNodeRecord _record = (StatusNodeRecord)e;
            record._lockSlimDispose.EnterWriteLock();
            try
            {
                    _record._socket.SendData(_record.Key.Item1, data);
                    _record?._timer_wait_crl_acp?.Change(_record._time_wait, Timeout.Infinite);
            }
            finally
            {
                record._lockSlimDispose.ExitWriteLock();
            }
        }, record, record._time_wait, Timeout.Infinite);
    }
    catch (Exception ex)
    {
        onEventLog?.Invoke(record, MethodInfo.GetCurrentMethod().Name, $"EXCEPTION::{ex.Message}. <-----------------------------------------------");
    }
}

Как только я получу подтверждение на стороне отправителя:

internal static void _dispose_wait_crl(this StatusNodeRecord record, _OnEventLog onEventLog)
{
    record._lockSlimDispose.EnterWriteLock();
    try
    {
            record?._timer_wait_crl_acp?.Change(Timeout.Infinite, Timeout.Infinite);
            record? _timer_wait_crl_acp?.Dispose();
            record._timer_wait_crl_acp = null;
    }
    finally
    {
        record._lockSlimDispose.ExitWriteLock();
    }
}

если смотрю логи на предмет в каком потоке исполняется код, повторной отправки и уничтожения, то вижу что в разных, в этоге событие на перезапуск перезапускается например в потоке №7, практически тут же приходит ответ от получателя, в потоке №8 выполняется уничтожение таймера, но спустя время выделенное на таймер происходит срабатывание функции в таймере, а там конечно же повторная отправка пакета, и перезапуск таймера, но по факту я его уже уничтожил, и перезапуск таймера не проходит, так как его просто нет. Почему Timer.Disppose() не отрабатывает ? как мне правильно его уничтожить !? Или это уже вариант для костылей типа переменной и Интерлок + Thread.VolatileRead() ? И тупо проверять есть 1 в переменной или нет ?


Ответы (0 шт):