From 4aa1e8ec27dbba197e89426eb091983f4cc7f34f Mon Sep 17 00:00:00 2001 From: Miguel Date: Sun, 29 Jun 2025 17:44:31 +0200 Subject: [PATCH] =?UTF-8?q?Implementada=20l=C3=B3gica=20de=20actualizaci?= =?UTF-8?q?=C3=B3n=20segura=20en=20PLCViewModel=20para=20evitar=20actualiz?= =?UTF-8?q?aciones=20concurrentes=20y=20mejorar=20la=20gesti=C3=B3n=20de?= =?UTF-8?q?=20tiempos=20de=20espera.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PLCViewModel.cs | 274 ++++++++++++++++++++++++++++-------------------- 1 file changed, 163 insertions(+), 111 deletions(-) diff --git a/PLCViewModel.cs b/PLCViewModel.cs index 71a1f30..fe0e06a 100644 --- a/PLCViewModel.cs +++ b/PLCViewModel.cs @@ -57,6 +57,13 @@ namespace LibS7Adv private DateTime _lastUpdateStartTime = DateTime.MinValue; private TimeSpan _updateTimeout = TimeSpan.FromSeconds(10); // Timeout para reintentar después de un tiempo + // Añadir protección contra loops infinitos + private readonly object _updateLock = new object(); + private int _concurrentUpdateCount = 0; + private const int MAX_CONCURRENT_UPDATES = 1; + private DateTime _lastUpdateAttempt = DateTime.MinValue; + private readonly TimeSpan _minUpdateInterval = TimeSpan.FromSeconds(2); + [ObservableProperty] PlcData plcData = new PlcData(); @@ -122,6 +129,14 @@ namespace LibS7Adv { IsConnected = false; PlcData.ConnectionStatus = "offline"; + + // Limpiar estado al desconectar + lock (_updateLock) + { + _isUpdating = false; + _concurrentUpdateCount = 0; + } + Instance = null; } @@ -130,10 +145,10 @@ namespace LibS7Adv { _isUpdating = true; _lastUpdateStartTime = DateTime.Now; - + // Actualizar cuando recibimos el evento - UpdateTagList(); - + SafeUpdateTagList(); + // Cuando la actualización se completa exitosamente, desactivar la bandera if (IsConfigured) { @@ -141,8 +156,45 @@ namespace LibS7Adv } else { - // Si no se pudo configurar, programar un reintento después de un tiempo - Task.Delay(1000).ContinueWith(_ => UpdateTagList()); + // Si no se pudo configurar, programar UN SOLO reintento después de un tiempo + // Solo si no hay otra actualización en curso + lock (_updateLock) + { + if (_concurrentUpdateCount == 0) + { + Task.Delay(2000).ContinueWith(_ => SafeUpdateTagList()); + } + } + } + } + + private void SafeUpdateTagList() + { + // Verificar si podemos hacer la actualización + lock (_updateLock) + { + // No permitir más de una actualización concurrente + if (_concurrentUpdateCount >= MAX_CONCURRENT_UPDATES) + return; + + // No actualizar muy frecuentemente + if (DateTime.Now - _lastUpdateAttempt < _minUpdateInterval) + return; + + _concurrentUpdateCount++; + _lastUpdateAttempt = DateTime.Now; + } + + try + { + UpdateTagList(); + } + finally + { + lock (_updateLock) + { + _concurrentUpdateCount--; + } } } @@ -150,7 +202,7 @@ namespace LibS7Adv { IsConfigured = false; _isUpdating = true; - + try { Instance?.UpdateTagList(ETagListDetails.IO | ETagListDetails.DB | ETagListDetails.M, true); // @@ -173,7 +225,7 @@ namespace LibS7Adv PlcData.LastError = "Not Connected"; return false; } - + // Verificar si estamos en proceso de actualización if (_isUpdating) { @@ -182,13 +234,13 @@ namespace LibS7Adv if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) { _lastUpdateStartTime = DateTime.Now; - UpdateTagList(); + SafeUpdateTagList(); } - + // No intentar leer durante la actualización return false; } - + if (sTag == null) { return false; } var tag = ParseTagAddress(sTag); @@ -213,10 +265,10 @@ namespace LibS7Adv { _isUpdating = true; _lastUpdateStartTime = DateTime.Now; - - // Iniciar actualización de tags - Task.Run(() => UpdateTagList()); - + + // Iniciar actualización de tags de forma segura + SafeUpdateTagList(); + PlcData.LastError = sTag + ": Tags no actualizados, reintentando..."; } else @@ -236,7 +288,7 @@ namespace LibS7Adv PlcData.LastError = "Not Connected"; return false; } - + // Verificar si estamos en proceso de actualización if (_isUpdating) { @@ -245,13 +297,13 @@ namespace LibS7Adv if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) { _lastUpdateStartTime = DateTime.Now; - UpdateTagList(); + SafeUpdateTagList(); } - + // No intentar escribir durante la actualización return false; } - + if (sTag == null) { return false; } var tag = ParseTagAddress(sTag); @@ -277,10 +329,10 @@ namespace LibS7Adv { _isUpdating = true; _lastUpdateStartTime = DateTime.Now; - - // Iniciar actualización de tags - Task.Run(() => UpdateTagList()); - + + // Iniciar actualización de tags de forma segura + SafeUpdateTagList(); + PlcData.LastError = sTag + ": Tags no actualizados, reintentando..."; } else @@ -300,7 +352,7 @@ namespace LibS7Adv PlcData.LastError = "Not Connected"; return ""; } - + // Verificar si estamos en proceso de actualización if (_isUpdating) { @@ -308,13 +360,13 @@ namespace LibS7Adv if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) { _lastUpdateStartTime = DateTime.Now; - UpdateTagList(); + SafeUpdateTagList(); } - + // No intentar leer durante la actualización return ""; } - + if (sTag == null) { return ""; } @@ -377,10 +429,10 @@ namespace LibS7Adv { _isUpdating = true; _lastUpdateStartTime = DateTime.Now; - - // Iniciar actualización de tags - Task.Run(() => UpdateTagList()); - + + // Iniciar actualización de tags de forma segura + SafeUpdateTagList(); + PlcData.LastError = sTag + ": Tags no actualizados, reintentando..."; } else @@ -404,13 +456,13 @@ namespace LibS7Adv if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) { _lastUpdateStartTime = DateTime.Now; - UpdateTagList(); + SafeUpdateTagList(); } - + // No intentar leer durante la actualización return false; } - + return Instance?.OutputArea.ReadBit(pByte, (byte)pBit) ?? false; } catch (Exception ex) @@ -420,10 +472,10 @@ namespace LibS7Adv { _isUpdating = true; _lastUpdateStartTime = DateTime.Now; - - // Iniciar actualización de tags - Task.Run(() => UpdateTagList()); - + + // Iniciar actualización de tags de forma segura + SafeUpdateTagList(); + PlcData.LastError = "Byte " + pByte + ", Bit " + pBit + ": Tags no actualizados, reintentando..."; } else @@ -445,13 +497,13 @@ namespace LibS7Adv if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) { _lastUpdateStartTime = DateTime.Now; - UpdateTagList(); + SafeUpdateTagList(); } - + // No intentar escribir durante la actualización return; } - + Instance?.InputArea.WriteBit(pByte, (byte)pBit, pValue); } catch (Exception ex) @@ -461,10 +513,10 @@ namespace LibS7Adv { _isUpdating = true; _lastUpdateStartTime = DateTime.Now; - - // Iniciar actualización de tags - Task.Run(() => UpdateTagList()); - + + // Iniciar actualización de tags de forma segura + SafeUpdateTagList(); + PlcData.LastError = "Byte " + pByte + ", Bit " + pBit + ": Tags no actualizados, reintentando..."; } else @@ -473,7 +525,7 @@ namespace LibS7Adv } } } - + public void EscribirTag(string pTag, SDataValue Value) { try @@ -483,7 +535,7 @@ namespace LibS7Adv PlcData.LastError = "Not Connected"; return; } - + // Verificar si estamos en proceso de actualización if (_isUpdating) { @@ -491,13 +543,13 @@ namespace LibS7Adv if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) { _lastUpdateStartTime = DateTime.Now; - UpdateTagList(); + SafeUpdateTagList(); } - + // No intentar escribir durante la actualización return; } - + Instance?.Write(pTag, Value); } catch (Exception ex) @@ -507,10 +559,10 @@ namespace LibS7Adv { _isUpdating = true; _lastUpdateStartTime = DateTime.Now; - - // Iniciar actualización de tags - Task.Run(() => UpdateTagList()); - + + // Iniciar actualización de tags de forma segura + SafeUpdateTagList(); + PlcData.LastError = pTag + ": Tags no actualizados, reintentando..."; } else @@ -519,7 +571,7 @@ namespace LibS7Adv } } } - + public SDataValue LeerTag(string pTag) { try @@ -529,7 +581,7 @@ namespace LibS7Adv PlcData.LastError = "Not Connected"; return new SDataValue(); } - + // Verificar si estamos en proceso de actualización if (_isUpdating) { @@ -537,13 +589,13 @@ namespace LibS7Adv if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) { _lastUpdateStartTime = DateTime.Now; - UpdateTagList(); + SafeUpdateTagList(); } - + // No intentar leer durante la actualización return new SDataValue(); } - + return Instance.Read(pTag); } catch (Exception ex) @@ -553,10 +605,10 @@ namespace LibS7Adv { _isUpdating = true; _lastUpdateStartTime = DateTime.Now; - - // Iniciar actualización de tags - Task.Run(() => UpdateTagList()); - + + // Iniciar actualización de tags de forma segura + SafeUpdateTagList(); + PlcData.LastError = pTag + ": Tags no actualizados, reintentando..."; } else @@ -566,7 +618,7 @@ namespace LibS7Adv return new SDataValue(); } } - + public void EscribirTagBool(string pTag, bool pValue) { try @@ -576,7 +628,7 @@ namespace LibS7Adv PlcData.LastError = "Not Connected"; return; } - + // Verificar si estamos en proceso de actualización if (_isUpdating) { @@ -584,13 +636,13 @@ namespace LibS7Adv if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) { _lastUpdateStartTime = DateTime.Now; - UpdateTagList(); + SafeUpdateTagList(); } - + // No intentar escribir durante la actualización return; } - + Instance?.WriteBool(pTag, pValue); } catch (Exception ex) @@ -600,10 +652,10 @@ namespace LibS7Adv { _isUpdating = true; _lastUpdateStartTime = DateTime.Now; - - // Iniciar actualización de tags - Task.Run(() => UpdateTagList()); - + + // Iniciar actualización de tags de forma segura + SafeUpdateTagList(); + PlcData.LastError = pTag + ": Tags no actualizados, reintentando..."; } else @@ -621,7 +673,7 @@ namespace LibS7Adv PlcData.LastError = "Not Connected"; return; } - + // Verificar si estamos en proceso de actualización if (_isUpdating) { @@ -629,13 +681,13 @@ namespace LibS7Adv if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) { _lastUpdateStartTime = DateTime.Now; - UpdateTagList(); + SafeUpdateTagList(); } - + // No intentar escribir durante la actualización return; } - + Instance?.WriteInt16(pTag, (short)pValue); } catch (Exception ex) @@ -645,10 +697,10 @@ namespace LibS7Adv { _isUpdating = true; _lastUpdateStartTime = DateTime.Now; - - // Iniciar actualización de tags - Task.Run(() => UpdateTagList()); - + + // Iniciar actualización de tags de forma segura + SafeUpdateTagList(); + PlcData.LastError = pTag + ": Tags no actualizados, reintentando..."; } else @@ -667,7 +719,7 @@ namespace LibS7Adv PlcData.LastError = "Not Connected"; return false; } - + // Verificar si estamos en proceso de actualización if (_isUpdating) { @@ -675,13 +727,13 @@ namespace LibS7Adv if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) { _lastUpdateStartTime = DateTime.Now; - UpdateTagList(); + SafeUpdateTagList(); } - + // No intentar leer durante la actualización return false; } - + bool result = Instance?.ReadBool(pTag) ?? false; return result; } @@ -692,10 +744,10 @@ namespace LibS7Adv { _isUpdating = true; _lastUpdateStartTime = DateTime.Now; - - // Iniciar actualización de tags - Task.Run(() => UpdateTagList()); - + + // Iniciar actualización de tags de forma segura + SafeUpdateTagList(); + PlcData.LastError = pTag + ": Tags no actualizados, reintentando..."; } else @@ -715,7 +767,7 @@ namespace LibS7Adv PlcData.LastError = "Not Connected"; return 0; } - + // Verificar si estamos en proceso de actualización if (_isUpdating) { @@ -723,13 +775,13 @@ namespace LibS7Adv if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) { _lastUpdateStartTime = DateTime.Now; - UpdateTagList(); + SafeUpdateTagList(); } - + // No intentar leer durante la actualización return 0; } - + int? result = Instance?.ReadInt16(pTag); return result; } @@ -740,10 +792,10 @@ namespace LibS7Adv { _isUpdating = true; _lastUpdateStartTime = DateTime.Now; - - // Iniciar actualización de tags - Task.Run(() => UpdateTagList()); - + + // Iniciar actualización de tags de forma segura + SafeUpdateTagList(); + PlcData.LastError = pTag + ": Tags no actualizados, reintentando..."; } else @@ -763,7 +815,7 @@ namespace LibS7Adv PlcData.LastError = "Not Connected"; return 0; } - + // Verificar si estamos en proceso de actualización if (_isUpdating) { @@ -771,13 +823,13 @@ namespace LibS7Adv if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) { _lastUpdateStartTime = DateTime.Now; - UpdateTagList(); + SafeUpdateTagList(); } - + // No intentar leer durante la actualización return 0; } - + int? result = Instance?.ReadInt32(pTag); return result; } @@ -788,10 +840,10 @@ namespace LibS7Adv { _isUpdating = true; _lastUpdateStartTime = DateTime.Now; - - // Iniciar actualización de tags - Task.Run(() => UpdateTagList()); - + + // Iniciar actualización de tags de forma segura + SafeUpdateTagList(); + PlcData.LastError = pTag + ": Tags no actualizados, reintentando..."; } else @@ -811,7 +863,7 @@ namespace LibS7Adv PlcData.LastError = "Not Connected"; return; } - + // Verificar si estamos en proceso de actualización if (_isUpdating) { @@ -819,13 +871,13 @@ namespace LibS7Adv if (DateTime.Now - _lastUpdateStartTime > _updateTimeout) { _lastUpdateStartTime = DateTime.Now; - UpdateTagList(); + SafeUpdateTagList(); } - + // No intentar escribir durante la actualización return; } - + Instance?.WriteInt32(pTag, pValue); } catch (Exception ex) @@ -835,10 +887,10 @@ namespace LibS7Adv { _isUpdating = true; _lastUpdateStartTime = DateTime.Now; - - // Iniciar actualización de tags - Task.Run(() => UpdateTagList()); - + + // Iniciar actualización de tags de forma segura + SafeUpdateTagList(); + PlcData.LastError = pTag + ": Tags no actualizados, reintentando..."; } else