5.0 KiB
Threading Optimization Summary for CtrEditor MCP Stability
Problem
CtrEditor's MCP server was experiencing freezing issues during simulations due to blocking Application.Current.Dispatcher.Invoke()
calls from background threads. This caused timeouts and made remote control via MCP unreliable during intensive simulations.
Root Cause Analysis
The issue was caused by multiple high-frequency timer callbacks using synchronous Dispatcher.Invoke()
calls:
OnTickSimulacion()
- Main simulation timer (15ms intervals)OnRefreshEvent()
- PLC update timer (10ms intervals)TimerCallback()
in osBase.cs - Object movement timersTimerCallbackRemoveHighlight()
in ObjectManipulationManager.cs - UI highlight removal
Threading Optimization Strategy
Replaced all blocking Dispatcher.Invoke()
calls with non-blocking Dispatcher.BeginInvoke()
calls using:
- Background priority to avoid blocking MCP operations
- Comprehensive error handling to prevent timer crashes
- Dispatcher availability checks to handle shutdown scenarios gracefully
Files Modified
1. MainViewModel.cs
OnTickSimulacion() method (lines ~1384-1410)
- Changed from
Invoke()
toBeginInvoke()
with Background priority - Added Application.Current and Dispatcher availability checks
- Added try-catch with debug logging
OnRefreshEvent() method (lines ~1399-1450)
- Changed from
Invoke()
toBeginInvoke()
with Background priority - Added Application.Current and Dispatcher availability checks
- Added try-catch with debug logging
2. ObjetosSim/osBase.cs
TimerCallback() method (lines ~937-961)
- Changed from
Invoke()
toBeginInvoke()
with Background priority - Added Application.Current and Dispatcher availability checks
- Added try-catch with debug logging
- Added
using System.Windows.Threading;
for DispatcherPriority
3. ObjectManipulationManager.cs
TimerCallbackRemoveHighlight() method (lines ~974-995)
- Changed from
Invoke()
toBeginInvoke()
with Background priority - Added Application.Current and Dispatcher availability checks
- Added try-catch with debug logging
- Added
using System.Windows.Threading;
for DispatcherPriority
4. Services/MCPServer.cs (Previously Optimized)
- Already using
InvokeAsync()
with timeouts - Added
IsDispatcherAvailable()
andSafeDispatcherInvokeAsync()
methods - Enhanced debug logging
Testing Results
Before Optimization
- MCP server would freeze during simulations
Application.Current.Dispatcher.Invoke()
calls blocked background threads- Frequent "CtrEditor not available" errors during intensive operations
After Optimization
- ✅ CtrEditor starts successfully with MCP responding
- ✅ Basic MCP operations work without freezing
- ✅ Simulation starts without blocking MCP server
- ✅ Build successful with all optimizations
TSNet Test Setup Verified
The existing project contains the requested test setup:
- 2 Tanks: "Tanque Origen" (source) and "Tanque Destino" (destination)
- 1 Pump: "Bomba Principal" configured and running
- 3 Pipes: "Tubería Entrada", "Tubería Intermedia", "Tubería Principal"
- Hydraulic Network: Properly connected in sequence for fluid flow
Technical Implementation Details
Threading Pattern Applied
// BEFORE (blocking)
Application.Current.Dispatcher.Invoke(() => {
// UI updates
});
// AFTER (non-blocking)
if (Application.Current == null) return;
if (Application.Current.Dispatcher == null || Application.Current.Dispatcher.HasShutdownStarted)
return;
Application.Current.Dispatcher.BeginInvoke(new Action(() => {
try {
// UI updates
}
catch (Exception ex) {
Debug.WriteLine($"Error in [MethodName]: {ex.Message}");
}
}), DispatcherPriority.Background);
Key Benefits
- Non-blocking execution: Background threads don't wait for UI thread
- MCP stability: Remote control operations remain responsive
- Error resilience: Timer exceptions don't crash the application
- Graceful shutdown: Proper checks for application lifecycle
Remaining Considerations
- WaitForUIUpdateAsync() in MainViewModel.cs still uses sync Invoke() - this is intentional for UI synchronization in non-critical paths
- MatrixPreviewViewModel.cs has some Dispatcher.Invoke() calls - these are in user-initiated operations, not high-frequency timers
- Monitor simulation performance during extended runs to ensure optimization effectiveness
Verification Commands
# Build verification
dotnet build CtrEditor.sln
# Search for remaining blocking calls
grep -r "Dispatcher\.Invoke(" --include="*.cs" .
# MCP testing
# Start CtrEditor -> list_objects -> start_simulation -> monitor status
Impact Assessment
This optimization significantly improves MCP stability during simulations while maintaining all existing functionality. The non-blocking approach ensures that high-frequency simulation timers don't interfere with remote control operations, making CtrEditor much more reliable for automated testing and monitoring scenarios.