How to Synchronize Multiple Engines (EngineSync)

Create, start, and use an EngineSync instance to align frame execution with external hardware timing.

This guide explains how to use the IEngineSync / CEngineSyncBase APIs to align engine frame progression with an external hardware timing reference, such as a discrete sync line, FPGA pulse, or external timing source.

The synchronization layer ensures that engine frame progression is aligned with an external hardware timing reference rather than relying solely on internal software timing.

1. Understand the Synchronization Model

How most projects use this: in a typical CoreEngine project, EngineSync is configured declaratively in the project's config file rather than called directly from your own model/app code, for example:
"EngineSync": {
  "stream": "SocketTCPTLMStream",
  "element": "LRU_KZ.TLMAiding.SystemEventNumber",
  "syncPerMS": "1000",
  "scale": { "engType": "float", "scale": 1000 },
  "affinity": "0,1,3,4-6",
  "priority": 6
}
The engine reads this configuration and creates, starts, and stops the synchronization instance internally. The manual Create() / Start() / WaitSync() / Stop() sequence below is framework-internal machinery, not something most CoreEngine model/app developers call directly - it's shown here for completeness and for engine integrators who need explicit control.

Synchronization is driven through a callback (syncSignalFn) that typically queries a stream connected to external hardware. The operational flow is:

This model guarantees deterministic frame timing when integrating with external systems such as FPGA clocks, real-time controllers, or hardware-triggered acquisition systems.

2. Create a Sync Instance with IEngineSync

Use the simple factory method for the common case:

MethodDescription
static CEngineSyncBase* Create(...) Constructs a concrete synchronization engine. Parameters:
  • streamName – Logical stream used to monitor the external sync source.
  • elementName – Specific element within the stream that carries the sync signal.
  • affinity – CPU affinity mask controlling which cores the sync thread may execute on.
  • syncSignalFn – Callback used to evaluate the synchronization condition (e.g., edge detection, level check).
Returns a configured synchronization instance ready for Start().

3. Or Create a Sync Instance with Explicit Scheduling (CEngineSyncBase)

Use the extended factory method when you need explicit control over engine type and thread scheduling:

MethodDescription
static CEngineSyncBase* Create(...) Extended factory allowing explicit engine type and scheduling configuration. Parameters:
  • streamName – Source stream providing the hardware sync signal.
  • elementName – Element within the stream to evaluate.
  • engType – Engine synchronization implementation type (e.g., polling, interrupt-driven, edge-triggered).
  • affinity – CPU affinity configuration for deterministic scheduling.
  • priority – Thread scheduling priority (typically real-time).
Use this overload for strict control over execution determinism and runtime behavior.

4. Start, Wait, and Stop

MethodDescription
Start() Activates the synchronization mechanism. Typically spawns or enables a real-time wait loop that blocks frame progression until the synchronization condition is satisfied.
WaitSync() Blocks execution until the synchronization condition defined by syncSignalFn is met. Typically invoked once per frame inside the engine loop, ensuring frame advancement occurs only after a valid external hardware synchronization event.
Stop() Stops synchronization and releases any associated execution resources, ensuring the engine no longer waits on the external sync condition.
virtual ~CEngineSyncBase() Virtual destructor to ensure proper cleanup of derived synchronization implementations.

5. Put It All Together

  1. Call Create() (either overload) with your stream name, element name, and scheduling parameters.
  2. Call Start() once to activate the sync mechanism.
  3. Inside the engine's per-frame loop, rely on the internal call to WaitSync() to block until the hardware sync condition is met before advancing the frame.
  4. Call Stop() when synchronization is no longer needed, and ensure the destructor runs to release resources.