diff --git a/Release/Scenario/MultiThreadTest.xml b/Release/Scenario/MultiThreadTest.xml new file mode 100755 index 0000000..ca3875d --- /dev/null +++ b/Release/Scenario/MultiThreadTest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Release/database/XNSim.db b/Release/database/XNSim.db index 12b6811..0cc271a 100644 Binary files a/Release/database/XNSim.db and b/Release/database/XNSim.db differ diff --git a/XNSimHtml/components/model-monitor.js b/XNSimHtml/components/model-monitor.js index 3d32fe9..71eb73b 100644 --- a/XNSimHtml/components/model-monitor.js +++ b/XNSimHtml/components/model-monitor.js @@ -2,6 +2,7 @@ class ModelMonitor extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); + this.monitorId = `model_monitor_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; this.monitorStatus = { isMonitoring: false, lastError: null @@ -10,39 +11,98 @@ class ModelMonitor extends HTMLElement { this.statusCheckInterval = null; this.chart = null; this.chartInitialized = false; + this.domainId = '10'; // 默认值 + this.isActive = false; } connectedCallback() { this.render(); + this.isActive = true; // 设置初始状态为激活 // 等待组件完全加载 setTimeout(() => { this.initializeComponent(); }, 100); } - initializeComponent() { - if (this.chartInitialized) return; - + async initializeComponent() { try { + // 确保图表被正确初始化 + if (this.chart) { + this.chart.destroy(); + this.chart = null; + } + + // 初始化图表 this.initChart(); - this.startStatusCheck(); + + // 检查当前监控状态 + const statusResponse = await fetch('/api/model-monitor/status'); + const statusData = await statusResponse.json(); + this.monitorStatus = statusData; + + // 如果已经在监控中,立即开始获取数据 + if (this.monitorStatus.isMonitoring) { + // 先获取一次数据 + await this.checkMonitorStatus(); + // 然后开始定时检查 + this.startStatusCheck(); + } + this.chartInitialized = true; } catch (error) { console.error('初始化组件失败:', error); + this.monitorStatus.lastError = error.message; + this.updateUI(); } } - disconnectedCallback() { - this.stopStatusCheck(); + // 修改 reactivate 方法 + reactivate() { + this.isActive = true; + // 如果已经在监控中,重新开始状态检查 + if (this.monitorStatus.isMonitoring) { + this.startStatusCheck(); + } } + // 修改 startStatusCheck 方法 startStatusCheck() { - this.checkMonitorStatus(); - this.statusCheckInterval = setInterval(() => { - this.checkMonitorStatus(); - }, 1000); + if (!this.isActive) return; + + // 如果已经有定时器在运行,先停止它 + this.stopStatusCheck(); + + let consecutiveErrors = 0; + const maxConsecutiveErrors = 3; + + const checkStatus = async () => { + if (!this.isActive) return; + + try { + await this.checkMonitorStatus(); + consecutiveErrors = 0; // 重置错误计数 + } catch (error) { + consecutiveErrors++; + console.error(`状态检查失败 (${consecutiveErrors}/${maxConsecutiveErrors}):`, error); + + if (consecutiveErrors >= maxConsecutiveErrors) { + console.error('连续错误次数过多,停止状态检查'); + this.stopStatusCheck(); + this.monitorStatus.lastError = '监控服务异常,请重新启动监控'; + this.updateUI(); + return; + } + } + }; + + // 立即执行一次 + checkStatus(); + + // 设置定时器,每秒执行一次 + this.statusCheckInterval = setInterval(checkStatus, 1000); } + // 修改 stopStatusCheck 方法 stopStatusCheck() { if (this.statusCheckInterval) { clearInterval(this.statusCheckInterval); @@ -50,6 +110,79 @@ class ModelMonitor extends HTMLElement { } } + // 修改 startMonitoring 方法 + async startMonitoring() { + const domainId = this.shadowRoot.querySelector('.domain-input').value.trim(); + this.domainId = domainId; + + // 验证域ID是否为有效的数字字符串 + if (!/^\d+$/.test(domainId)) { + console.error('域ID必须是有效的数字'); + return; + } + + try { + // 首先检查DDS监控状态 + const ddsStatusResponse = await fetch('/api/dds-monitor/status'); + const ddsStatusData = await ddsStatusResponse.json(); + + // 如果DDS监控未初始化,先初始化DDS监控 + if (!ddsStatusData.isInitialized) { + const ddsInitResponse = await fetch('/api/dds-monitor/initialize', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + domainId, + monitorId: this.monitorId + }) + }); + + if (!ddsInitResponse.ok) { + const errorData = await ddsInitResponse.json(); + console.error('DDS监控初始化失败:', errorData.error); + return; + } + } + + // 启动模型监控 + const response = await fetch('/api/model-monitor/start', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ domainId }) + }); + const data = await response.json(); + if (response.ok) { + this.monitorStatus = data.status; + this.updateUI(); + this.startStatusCheck(); // 直接启动状态检查,不需要检查 isActive + } else { + console.error('启动监控失败:', data.error); + } + } catch (error) { + console.error('启动监控失败:', error); + } + } + + disconnectedCallback() { + this.isActive = false; + this.stopStatusCheck(); + // 注销监控器 + fetch('/api/dds-monitor/unregister', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ monitorId: this.monitorId }) + }).catch(error => { + console.error('注销监控器失败:', error); + }); + // 不要在这里销毁图表实例,让它在重新激活时重新创建 + } + async checkMonitorStatus() { try { // 获取监控状态 @@ -61,31 +194,43 @@ class ModelMonitor extends HTMLElement { try { // 获取模型信息 const modelResponse = await fetch('/api/model-monitor/model-info'); + if (!modelResponse.ok) { + throw new Error(`模型信息获取失败: ${modelResponse.status}`); + } const modelData = await modelResponse.json(); if (!modelResponse.ok) { console.error('获取模型信息失败:', modelData.error || modelData.message); this.monitorStatus.lastError = modelData.error || modelData.message; - this.modelInfo = null; + // 保持原有数据不变 } else { - this.modelInfo = modelData.data; - this.monitorStatus.lastError = null; + // 只有在数据发生变化时才更新 + if (JSON.stringify(this.modelInfo) !== JSON.stringify(modelData.data)) { + this.modelInfo = modelData.data; + this.monitorStatus.lastError = null; + // 确保图表存在 + if (!this.chart) { + this.initChart(); + } + // 更新UI + this.updateUI(); + } } } catch (error) { - console.error('获取模型信息失败:', error); - this.monitorStatus.lastError = error.message; - this.modelInfo = null; + console.warn('获取模型信息失败:', error); + // 保持原有数据不变 } } else { - this.modelInfo = null; - this.monitorStatus.lastError = null; + // 只有在状态发生变化时才更新 + if (this.modelInfo !== null) { + this.modelInfo = null; + this.monitorStatus.lastError = null; + this.updateUI(); + } } - - this.updateUI(); } catch (error) { console.error('获取监控状态失败:', error); this.monitorStatus.lastError = error.message; - this.modelInfo = null; this.updateUI(); } } @@ -166,57 +311,6 @@ class ModelMonitor extends HTMLElement { } } - async startMonitoring() { - const domainId = this.shadowRoot.querySelector('.domain-input').value.trim(); - - // 验证域ID是否为有效的数字字符串 - if (!/^\d+$/.test(domainId)) { - console.error('域ID必须是有效的数字'); - return; - } - - try { - // 首先检查DDS监控状态 - const ddsStatusResponse = await fetch('/api/dds-monitor/status'); - const ddsStatusData = await ddsStatusResponse.json(); - - // 如果DDS监控未初始化,先初始化DDS监控 - if (!ddsStatusData.isInitialized) { - const ddsInitResponse = await fetch('/api/dds-monitor/initialize', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ domainId }) - }); - - if (!ddsInitResponse.ok) { - const errorData = await ddsInitResponse.json(); - console.error('DDS监控初始化失败:', errorData.error); - return; - } - } - - // 启动模型监控 - const response = await fetch('/api/model-monitor/start', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ domainId }) - }); - const data = await response.json(); - if (response.ok) { - this.monitorStatus = data.status; - this.updateUI(); - } else { - console.error('启动监控失败:', data.error); - } - } catch (error) { - console.error('启动监控失败:', error); - } - } - async stopMonitoring() { try { const response = await fetch('/api/model-monitor/stop', { @@ -506,6 +600,7 @@ class ModelMonitor extends HTMLElement { `; } + // 修改 initChart 方法 initChart() { const chartElement = this.shadowRoot.querySelector('#model-chart'); if (!chartElement) { @@ -530,6 +625,7 @@ class ModelMonitor extends HTMLElement { // 销毁已存在的图表实例 if (this.chart) { this.chart.destroy(); + this.chart = null; } // 创建新的图表实例 @@ -577,7 +673,9 @@ class ModelMonitor extends HTMLElement { } updateChartData() { - if (!this.chart || !this.modelInfo || !Array.isArray(this.modelInfo)) return; + if (!this.chart || !this.modelInfo || !Array.isArray(this.modelInfo)) { + return; + } const isFrequency = this.shadowRoot.querySelector('#display-type-switch').checked; const currentTime = new Date().toLocaleTimeString(); diff --git a/XNSimHtml/components/simulation-monitor.js b/XNSimHtml/components/simulation-monitor.js index cf4fcef..67241b2 100644 --- a/XNSimHtml/components/simulation-monitor.js +++ b/XNSimHtml/components/simulation-monitor.js @@ -2,6 +2,7 @@ class SimulationMonitor extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); + this.monitorId = `simulation_monitor_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; this.monitorStatus = { isMonitoring: false, lastError: null @@ -11,39 +12,101 @@ class SimulationMonitor extends HTMLElement { this.statusCheckInterval = null; this.chart = null; this.chartInitialized = false; + this.domainId = '10'; // 默认值 + this.isActive = false; + this.initializing = false; } connectedCallback() { this.render(); + this.isActive = true; // 设置初始状态为激活 // 等待组件完全加载 setTimeout(() => { this.initializeComponent(); }, 100); } - initializeComponent() { - if (this.chartInitialized) return; - - try { - this.initChart(); - this.startStatusCheck(); - this.chartInitialized = true; - } catch (error) { - console.error('初始化组件失败:', error); - } - } - - disconnectedCallback() { - this.stopStatusCheck(); + // 重新激活组件 + reactivate() { + if (this.isActive) return; // 如果已经激活,直接返回 + this.isActive = true; + // 强制重新初始化 + this.chartInitialized = false; + this.chart = null; + this.initializeComponent(); } + // 修改 startStatusCheck 方法 startStatusCheck() { - this.checkMonitorStatus(); + if (!this.isActive) return; + + // 清除可能存在的旧定时器 + this.stopStatusCheck(); + + // 设置定时器,每秒执行一次 this.statusCheckInterval = setInterval(() => { - this.checkMonitorStatus(); + if (this.isActive && this.monitorStatus.isMonitoring) { + this.checkMonitorStatus(); + } else { + // 如果监控已停止,清除定时器 + this.stopStatusCheck(); + } }, 1000); } + // 修改 checkMonitorStatus 方法 + async checkMonitorStatus() { + if (!this.monitorStatus.isMonitoring) return; + + try { + // 获取监控状态 + const statusResponse = await fetch('/api/system-monitor/status'); + const statusData = await statusResponse.json(); + this.monitorStatus = statusData; + + // 只有在监控状态为true时才获取详细信息 + if (this.monitorStatus.isMonitoring) { + // 使用 Promise.all 并行获取系统信息和线程信息 + const [systemResponse, threadResponse] = await Promise.all([ + fetch('/api/system-monitor/system-info'), + fetch('/api/system-monitor/thread-info') + ]); + + if (systemResponse.ok) { + const systemData = await systemResponse.json(); + this.systemInfo = systemData.data; + } + + if (threadResponse.ok) { + const threadData = await threadResponse.json(); + this.threadInfo = threadData.data; + // 确保图表存在并更新 + if (!this.chart) { + this.initChart(); + } + } + + // 只在成功获取数据后更新UI + this.updateUI(); + } else { + // 如果监控已停止,清空数据 + this.systemInfo = null; + this.threadInfo = null; + // 停止状态检查 + this.stopStatusCheck(); + // 更新UI显示停止状态 + this.updateUI(); + } + } catch (error) { + console.error('获取监控状态失败:', error); + this.monitorStatus.lastError = error.message; + this.updateUI(); + // 发生错误时也停止状态检查 + this.stopStatusCheck(); + } + } + + // 修改 stopStatusCheck 方法 stopStatusCheck() { if (this.statusCheckInterval) { clearInterval(this.statusCheckInterval); @@ -51,30 +114,119 @@ class SimulationMonitor extends HTMLElement { } } - async checkMonitorStatus() { + // 修改 startMonitoring 方法 + async startMonitoring() { + const domainId = this.shadowRoot.querySelector('.domain-input').value.trim(); + this.domainId = domainId; + + // 验证域ID是否为有效的数字字符串 + if (!/^\d+$/.test(domainId)) { + console.error('域ID必须是有效的数字'); + return; + } + + // 如果已经在监控中,直接返回 + if (this.monitorStatus.isMonitoring) { + console.log('监控已经在运行中'); + return; + } + try { - // 获取监控状态 + // 首先检查DDS监控状态 + const ddsStatusResponse = await fetch('/api/dds-monitor/status'); + const ddsStatusData = await ddsStatusResponse.json(); + + // 如果DDS监控未初始化,先初始化DDS监控 + if (!ddsStatusData.isInitialized) { + const ddsInitResponse = await fetch('/api/dds-monitor/initialize', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + domainId, + monitorId: this.monitorId + }) + }); + + if (!ddsInitResponse.ok) { + const errorData = await ddsInitResponse.json(); + console.error('DDS监控初始化失败:', errorData.error); + return; + } + } + + // 启动系统监控 + const response = await fetch('/api/system-monitor/start', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ domainId }) + }); + const data = await response.json(); + if (response.ok) { + this.monitorStatus = data.status; + this.updateUI(); + // 只有在没有运行中的状态检查时才启动新的检查 + if (!this.statusCheckInterval) { + this.startStatusCheck(); + } + } else { + console.error('启动监控失败:', data.error); + } + } catch (error) { + console.error('启动监控失败:', error); + } + } + + disconnectedCallback() { + this.isActive = false; + this.stopStatusCheck(); + // 注销监控器 + fetch('/api/dds-monitor/unregister', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ monitorId: this.monitorId }) + }).catch(error => { + console.error('注销监控器失败:', error); + }); + // 不要在这里销毁图表实例,让它在重新激活时重新创建 + } + + async initializeComponent() { + if (this.initializing) return; // 防止重复初始化 + this.initializing = true; + + try { + // 确保图表被正确初始化 + if (this.chart) { + this.chart.destroy(); + this.chart = null; + } + + // 初始化图表 + this.initChart(); + + // 检查当前监控状态 const statusResponse = await fetch('/api/system-monitor/status'); const statusData = await statusResponse.json(); this.monitorStatus = statusData; - if (this.monitorStatus.isMonitoring) { - // 获取系统信息 - const systemResponse = await fetch('/api/system-monitor/system-info'); - const systemData = await systemResponse.json(); - this.systemInfo = systemData.data; - - // 获取线程信息 - const threadResponse = await fetch('/api/system-monitor/thread-info'); - const threadData = await threadResponse.json(); - this.threadInfo = threadData.data; + // 如果已经在监控中,开始状态检查 + if (this.monitorStatus.isMonitoring && !this.statusCheckInterval) { + this.startStatusCheck(); } - - this.updateUI(); + + this.chartInitialized = true; } catch (error) { - console.error('获取监控状态失败:', error); + console.error('初始化组件失败:', error); this.monitorStatus.lastError = error.message; this.updateUI(); + } finally { + this.initializing = false; } } @@ -259,57 +411,6 @@ class SimulationMonitor extends HTMLElement { } } - async startMonitoring() { - const domainId = this.shadowRoot.querySelector('.domain-input').value.trim(); - - // 验证域ID是否为有效的数字字符串 - if (!/^\d+$/.test(domainId)) { - console.error('域ID必须是有效的数字'); - return; - } - - try { - // 首先检查DDS监控状态 - const ddsStatusResponse = await fetch('/api/dds-monitor/status'); - const ddsStatusData = await ddsStatusResponse.json(); - - // 如果DDS监控未初始化,先初始化DDS监控 - if (!ddsStatusData.isInitialized) { - const ddsInitResponse = await fetch('/api/dds-monitor/initialize', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ domainId }) - }); - - if (!ddsInitResponse.ok) { - const errorData = await ddsInitResponse.json(); - console.error('DDS监控初始化失败:', errorData.error); - return; - } - } - - // 启动系统监控 - const response = await fetch('/api/system-monitor/start', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ domainId }) - }); - const data = await response.json(); - if (response.ok) { - this.monitorStatus = data.status; - this.updateUI(); - } else { - console.error('启动监控失败:', data.error); - } - } catch (error) { - console.error('启动监控失败:', error); - } - } - async stopMonitoring() { try { const response = await fetch('/api/system-monitor/stop', { @@ -700,6 +801,7 @@ class SimulationMonitor extends HTMLElement { // 销毁已存在的图表实例 if (this.chart) { this.chart.destroy(); + this.chart = null; } // 创建新的图表实例 @@ -747,7 +849,9 @@ class SimulationMonitor extends HTMLElement { } updateChartData() { - if (!this.chart || !this.threadInfo || !Array.isArray(this.threadInfo)) return; + if (!this.chart || !this.threadInfo || !Array.isArray(this.threadInfo)) { + return; + } const isFrequency = this.shadowRoot.querySelector('#display-type-switch').checked; const currentTime = new Date().toLocaleTimeString(); diff --git a/XNSimHtml/routes/DDSMonitor.js b/XNSimHtml/routes/DDSMonitor.js index a1b0a62..3ed5ee7 100644 --- a/XNSimHtml/routes/DDSMonitor.js +++ b/XNSimHtml/routes/DDSMonitor.js @@ -6,22 +6,32 @@ const { initializeMonitor, cleanupMonitor } = require('../utils/systemMonitor'); let monitorStatus = { isInitialized: false, domainId: null, - lastError: null + lastError: null, + activeMonitors: new Set() // 添加活跃监控器集合 }; // 初始化监控服务 router.post('/initialize', async (req, res) => { try { - const { domainId } = req.body; + const { domainId, monitorId } = req.body; - if (!domainId) { - return res.status(400).json({ error: '缺少必要的domainId参数' }); + if (!domainId || !monitorId) { + return res.status(400).json({ error: '缺少必要的参数' }); } + // 如果已经初始化,检查是否是新的监控器 if (monitorStatus.isInitialized) { - return res.status(400).json({ error: '监控服务已经初始化' }); + if (monitorStatus.domainId !== domainId) { + return res.status(400).json({ error: 'DDS域ID不匹配' }); + } + monitorStatus.activeMonitors.add(monitorId); + return res.json({ + message: '监控器已注册', + status: monitorStatus + }); } + // 首次初始化 const result = initializeMonitor(domainId); if (result && result.includes('失败')) { monitorStatus.lastError = result; @@ -31,6 +41,7 @@ router.post('/initialize', async (req, res) => { monitorStatus.isInitialized = true; monitorStatus.domainId = domainId; monitorStatus.lastError = null; + monitorStatus.activeMonitors.add(monitorId); res.json({ message: '监控服务初始化成功', @@ -43,28 +54,35 @@ router.post('/initialize', async (req, res) => { } }); -// 清理监控服务 -router.post('/cleanup', async (req, res) => { +// 注销监控器 +router.post('/unregister', async (req, res) => { try { - if (!monitorStatus.isInitialized) { - return res.status(400).json({ error: '监控服务未初始化' }); + const { monitorId } = req.body; + + if (!monitorId) { + return res.status(400).json({ error: '缺少必要的monitorId参数' }); } - cleanupMonitor(); - monitorStatus = { - isInitialized: false, - domainId: null, - lastError: null - }; + monitorStatus.activeMonitors.delete(monitorId); + + // 如果没有活跃的监控器了,清理资源 + if (monitorStatus.activeMonitors.size === 0) { + cleanupMonitor(); + monitorStatus = { + isInitialized: false, + domainId: null, + lastError: null, + activeMonitors: new Set() + }; + } res.json({ - message: '监控服务清理成功', + message: '监控器注销成功', status: monitorStatus }); } catch (error) { - console.error('清理监控服务失败:', error); - monitorStatus.lastError = error.message; - res.status(500).json({ error: '清理监控服务失败', message: error.message }); + console.error('注销监控器失败:', error); + res.status(500).json({ error: '注销监控器失败', message: error.message }); } }); diff --git a/XNSimHtml/routes/SystemMonitor.js b/XNSimHtml/routes/SystemMonitor.js index 47ec011..b74d706 100644 --- a/XNSimHtml/routes/SystemMonitor.js +++ b/XNSimHtml/routes/SystemMonitor.js @@ -5,7 +5,8 @@ const { startMonitorSystemInfo, stopMonitorSystemInfo, getSystemInfo, getAllThre // 存储监控服务的状态 let monitorStatus = { isMonitoring: false, - lastError: null + lastError: null, + lastUpdateTime: null // 添加最后更新时间 }; // 存储线程频率历史数据 @@ -72,6 +73,7 @@ router.post('/start', async (req, res) => { monitorStatus.isMonitoring = true; monitorStatus.lastError = null; + monitorStatus.lastUpdateTime = Date.now(); res.json({ message: '系统监控启动成功', @@ -166,12 +168,21 @@ router.get('/thread-info', async (req, res) => { return res.status(400).json({ error: '系统监控未在运行' }); } + // 检查更新频率 + const now = Date.now(); + if (monitorStatus.lastUpdateTime && (now - monitorStatus.lastUpdateTime) < 900) { // 900ms 作为最小间隔 + return res.status(429).json({ error: '请求过于频繁' }); + } + const result = getAllThreadInfo(); if (result && result.includes('失败')) { monitorStatus.lastError = result; return res.status(500).json({ error: result }); } + // 更新最后更新时间 + monitorStatus.lastUpdateTime = now; + // 解析JSON字符串 const data = JSON.parse(result); if (!data.threadStatus) { @@ -180,12 +191,21 @@ router.get('/thread-info', async (req, res) => { const threadStatus = data.threadStatus; + function isNullOrUndefined(val) { + return val === undefined || val === null; + } + // 构造响应数据 const responseData = Object.entries(threadStatus).map(([threadId, thread]) => { - if (!thread.threadCurrentFrequency || !thread.threadSetFrequency || - !thread.threadName || !thread.threadAffinity || - !thread.threadPro || !thread.threadRunCount || - !thread.threadStatus) { + if ( + isNullOrUndefined(thread.threadCurrentFrequency) || + isNullOrUndefined(thread.threadSetFrequency) || + isNullOrUndefined(thread.threadName) || + isNullOrUndefined(thread.threadAffinity) || + isNullOrUndefined(thread.threadPro) || + isNullOrUndefined(thread.threadRunCount) || + isNullOrUndefined(thread.threadStatus) + ) { throw new Error('线程数据不完整'); }