From a65dfab897977d72afc8827d682a3850359d0927 Mon Sep 17 00:00:00 2001 From: SugarChes Date: Sat, 15 Aug 2026 18:39:26 +0800 Subject: [PATCH] fix: synchronize module data cache cleanup --- .../FrmBaseAccraditation.cs | 2 +- 插件库/Lskj.Control/AuditPanelEx.cs | 2 +- 插件库/Lskj.Control/Model/MyControl.cs | 2 +- 插件库/Lskj.Control/ModuleEx.cs | 2 +- 插件库/Lskj.Control/ModuleGridDetailEx.cs | 2 +- 插件库/Lskj.Control/ModuleGridEx.cs | 2 +- 插件库/Lskj.Control/ReplacementDetailEx.cs | 2 +- .../Lskj.PubAccraditation/FrmAccraditation.cs | 2 +- 插件库/Lskj.PubModuleDetail/FrmMain.cs | 78 ++++++++------ 插件库/Lskj.Report/FrmMain.cs | 2 +- 插件库/Lskj.Util/extend/DataTableExtend.cs | 101 +++++++++++++----- 11 files changed, 126 insertions(+), 71 deletions(-) diff --git a/插件库/Lskj.BaseAccraditation/FrmBaseAccraditation.cs b/插件库/Lskj.BaseAccraditation/FrmBaseAccraditation.cs index e966fa4..033580f 100644 --- a/插件库/Lskj.BaseAccraditation/FrmBaseAccraditation.cs +++ b/插件库/Lskj.BaseAccraditation/FrmBaseAccraditation.cs @@ -219,7 +219,7 @@ namespace Lskj.BaseAccraditation } if (SysModel != null && SysModel.DataCaches != null) { - SysModel.DataCaches.Remove(this); + SysModel.DataCaches.RemoveCache(this); } } catch diff --git a/插件库/Lskj.Control/AuditPanelEx.cs b/插件库/Lskj.Control/AuditPanelEx.cs index f9e9e18..ca344fc 100644 --- a/插件库/Lskj.Control/AuditPanelEx.cs +++ b/插件库/Lskj.Control/AuditPanelEx.cs @@ -94,7 +94,7 @@ namespace Lskj.Control { if (SysModel != null && SysModel.DataCaches != null) { - SysModel.DataCaches.Remove(this); + SysModel.DataCaches.RemoveCache(this); } } catch diff --git a/插件库/Lskj.Control/Model/MyControl.cs b/插件库/Lskj.Control/Model/MyControl.cs index d47a8bd..fb0416b 100644 --- a/插件库/Lskj.Control/Model/MyControl.cs +++ b/插件库/Lskj.Control/Model/MyControl.cs @@ -6892,7 +6892,7 @@ namespace Lskj.Control.Model { if (Model != null && Model.DataCaches != null) { - Model.DataCaches.Remove(this); + Model.DataCaches.RemoveCache(this); } } catch diff --git a/插件库/Lskj.Control/ModuleEx.cs b/插件库/Lskj.Control/ModuleEx.cs index b913d94..0e7739d 100644 --- a/插件库/Lskj.Control/ModuleEx.cs +++ b/插件库/Lskj.Control/ModuleEx.cs @@ -261,7 +261,7 @@ namespace Lskj.Control { if (Model != null && Model.DataCaches != null) { - Model.DataCaches.Remove(this); + Model.DataCaches.RemoveCache(this); } } catch diff --git a/插件库/Lskj.Control/ModuleGridDetailEx.cs b/插件库/Lskj.Control/ModuleGridDetailEx.cs index d39b165..bf78a5a 100644 --- a/插件库/Lskj.Control/ModuleGridDetailEx.cs +++ b/插件库/Lskj.Control/ModuleGridDetailEx.cs @@ -193,7 +193,7 @@ namespace Lskj.Control { if (Model != null && Model.DataCaches != null) { - Model.DataCaches.Remove(this); + Model.DataCaches.RemoveCache(this); } } catch diff --git a/插件库/Lskj.Control/ModuleGridEx.cs b/插件库/Lskj.Control/ModuleGridEx.cs index 35b269f..17a3460 100644 --- a/插件库/Lskj.Control/ModuleGridEx.cs +++ b/插件库/Lskj.Control/ModuleGridEx.cs @@ -3780,7 +3780,7 @@ namespace Lskj.Control { if (Model != null && Model.DataCaches != null) { - Model.DataCaches.Remove(this); + Model.DataCaches.RemoveCache(this); } } catch diff --git a/插件库/Lskj.Control/ReplacementDetailEx.cs b/插件库/Lskj.Control/ReplacementDetailEx.cs index 39f4126..de89502 100644 --- a/插件库/Lskj.Control/ReplacementDetailEx.cs +++ b/插件库/Lskj.Control/ReplacementDetailEx.cs @@ -121,7 +121,7 @@ namespace Lskj.Control { if (Model != null && Model.DataCaches != null) { - Model.DataCaches.Remove(this); + Model.DataCaches.RemoveCache(this); } } catch diff --git a/插件库/Lskj.PubAccraditation/FrmAccraditation.cs b/插件库/Lskj.PubAccraditation/FrmAccraditation.cs index 803a5c1..6c5eb88 100644 --- a/插件库/Lskj.PubAccraditation/FrmAccraditation.cs +++ b/插件库/Lskj.PubAccraditation/FrmAccraditation.cs @@ -89,7 +89,7 @@ namespace Lskj.PubAccraditation } if (SysModel != null && SysModel.DataCaches != null) { - SysModel.DataCaches.Remove(this); + SysModel.DataCaches.RemoveCache(this); } } catch diff --git a/插件库/Lskj.PubModuleDetail/FrmMain.cs b/插件库/Lskj.PubModuleDetail/FrmMain.cs index 13ec5c5..810ec37 100644 --- a/插件库/Lskj.PubModuleDetail/FrmMain.cs +++ b/插件库/Lskj.PubModuleDetail/FrmMain.cs @@ -211,13 +211,14 @@ namespace Lskj.PubModuleDetail Dictionary dataCaches = Model != null ? Model.DataCaches : null; - if (dataCaches == null || !AreDataCacheTasksCompleted(dataCaches)) + HashSet completedTasks; + if (dataCaches == null || + !TryDetachCompletedCacheTasks(dataCaches, out completedTasks)) { return; } - DisposeCompletedCacheTasks(dataCaches); - dataCaches.Clear(); + DisposeCompletedCacheTasks(completedTasks); } /// @@ -225,34 +226,10 @@ namespace Lskj.PubModuleDetail /// Task.Result 在等待时可能创建底层等待对象,仅清空字典 /// 不会立即释放这些句柄。 /// - private static void DisposeCompletedCacheTasks( - Dictionary dataCaches) + private static void DisposeCompletedCacheTasks(IEnumerable tasks) { - HashSet tasks = new HashSet(); - foreach (Hashtable cache in dataCaches.Values) - { - if (cache == null) - { - continue; - } - - foreach (object value in cache.Values) - { - Task task = value as Task; - if (task != null) - { - tasks.Add(task); - } - } - } - foreach (Task task in tasks) { - if (!task.IsCompleted) - { - continue; - } - try { task.Dispose(); @@ -264,27 +241,58 @@ namespace Lskj.PubModuleDetail } /// - /// 并行初始化仍在运行时不能清空缓存字典,后台任务还会读取或追加其中的数据。 + /// 仅当并行初始化全部完成时,才在同一同步区间摘除缓存任务。 + /// AddTask 使用同一个字典实例加锁,避免检查后又插入新任务。 /// - private static bool AreDataCacheTasksCompleted(Dictionary dataCaches) + private static bool TryDetachCompletedCacheTasks( + Dictionary dataCaches, + out HashSet completedTasks) { + completedTasks = new HashSet(); try { - foreach (Hashtable cacheValues in dataCaches.Values) + lock (dataCaches) { - foreach (object value in cacheValues.Values) + foreach (Hashtable cacheValues in dataCaches.Values) { - Task task = value as Task; - if (task != null && !task.IsCompleted) + if (cacheValues == null) { - return false; + continue; + } + + foreach (object value in cacheValues.Values) + { + Task task = value as Task; + if (task == null) + { + continue; + } + + try + { + if (!task.IsCompleted) + { + completedTasks.Clear(); + return false; + } + } + catch (ObjectDisposedException) + { + continue; + } + + completedTasks.Add(task); } } + + dataCaches.Clear(); } + return true; } catch (InvalidOperationException) { + completedTasks.Clear(); return false; } } diff --git a/插件库/Lskj.Report/FrmMain.cs b/插件库/Lskj.Report/FrmMain.cs index 1e580c3..54b9f7b 100644 --- a/插件库/Lskj.Report/FrmMain.cs +++ b/插件库/Lskj.Report/FrmMain.cs @@ -115,7 +115,7 @@ namespace Lskj.Report try { - model.DataCaches.Clear(); + model.DataCaches.ClearCaches(); } catch (Exception ex) { diff --git a/插件库/Lskj.Util/extend/DataTableExtend.cs b/插件库/Lskj.Util/extend/DataTableExtend.cs index 9f72d71..783f440 100644 --- a/插件库/Lskj.Util/extend/DataTableExtend.cs +++ b/插件库/Lskj.Util/extend/DataTableExtend.cs @@ -197,26 +197,31 @@ namespace Lskj.Util value = default; return false; } - if (dic.ContainsKey(control)) + + Task task; + lock (dic) { - if (dic[control].ContainsKey(key)) - { - Task task = dic[control][key] as Task; - value = task.Result; - task.Dispose(); - return true; - } - else + Hashtable cache; + if (!dic.TryGetValue(control, out cache) || + cache == null || + !cache.ContainsKey(key)) { value = default; return false; } + + task = cache[key] as Task; } - else + + if (task == null) { value = default; return false; } + + value = task.Result; + task.Dispose(); + return true; } catch (Exception ex) { @@ -237,14 +242,23 @@ namespace Lskj.Util { try { - if (cachesDic.ContainsKey(control) && cachesDic[control].ContainsKey(key)) - { - return (Task)cachesDic[control][key]; - } - else + if (cachesDic == null) { return default; } + + lock (cachesDic) + { + Hashtable cache; + if (cachesDic.TryGetValue(control, out cache) && + cache != null && + cache.ContainsKey(key)) + { + return cache[key] as Task; + } + } + + return default; } catch (Exception ex) { @@ -253,6 +267,36 @@ namespace Lskj.Util } } /// + /// 在线程安全的同步区间内移除控件缓存。 + /// + public static bool RemoveCache(this Dictionary cachesDic, object control) + { + if (cachesDic == null) + { + return false; + } + + lock (cachesDic) + { + return cachesDic.Remove(control); + } + } + /// + /// 在线程安全的同步区间内清空任务缓存。 + /// + public static void ClearCaches(this Dictionary cachesDic) + { + if (cachesDic == null) + { + return; + } + + lock (cachesDic) + { + cachesDic.Clear(); + } + } + /// /// 添加任务 /// /// @@ -262,20 +306,23 @@ namespace Lskj.Util /// public static Task AddTask(this Dictionary cachesDic, object control, string key, Task task) { - Hashtable cachesHash = new Hashtable(); - if (!cachesDic.ContainsKey(control)) + lock (cachesDic) { - cachesDic.Add(control, cachesHash); - } - else - { - cachesHash = cachesDic[control]; - } - cachesHash.Add(key, task); - if (task.Status == TaskStatus.Created) - { - task.Start(SchedulerUtil); + Hashtable cachesHash; + if (!cachesDic.TryGetValue(control, out cachesHash) || + cachesHash == null) + { + cachesHash = new Hashtable(); + cachesDic[control] = cachesHash; + } + + cachesHash.Add(key, task); + if (task.Status == TaskStatus.Created) + { + task.Start(SchedulerUtil); + } } + return task; }