CtrEditor/THREADING_OPTIMIZATION_SUMM...

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:

  1. OnTickSimulacion() - Main simulation timer (15ms intervals)
  2. OnRefreshEvent() - PLC update timer (10ms intervals)
  3. TimerCallback() in osBase.cs - Object movement timers
  4. TimerCallbackRemoveHighlight() 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() to BeginInvoke() with Background priority
  • Added Application.Current and Dispatcher availability checks
  • Added try-catch with debug logging

OnRefreshEvent() method (lines ~1399-1450)

  • Changed from Invoke() to BeginInvoke() 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() to BeginInvoke() 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() to BeginInvoke() 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() and SafeDispatcherInvokeAsync() 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

  1. Non-blocking execution: Background threads don't wait for UI thread
  2. MCP stability: Remote control operations remain responsive
  3. Error resilience: Timer exceptions don't crash the application
  4. 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.