Проблема с 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 в переменной или нет ?