Time Synchronization Service
The time synchronization service is the main interface to model a participant’s behavior in case virtual time synchronization shall be used. It allows configuring a simulation step length and set the simulation step that will be executed repeatedly.
Note
Here, only a brief overview of the API is given, see Virtual Time Synchronization for more information on time synchronization with the SIL Kit.
Using the Time Synchronization Service
Once the time synchronization service was created, the participant will automatically partake in the virtual time synchronization. Setting a simulation step, even an empty one, is mandatory for participants using the time synchronization service interface. Please note that the lifecycle service and the time synchronization service can only be created once. Calling these methods more than once throws an exception. The following code creates a lifecycle service, a time synchronization service and defines the simulation step handler with the participant’s step duration:
SilKit::Services::Orchestration::LifecycleConfiguration lc
{SilKit::Services::Orchestration::OperationMode::Coordinated};
auto* lifecycleService = participant->CreateLifecycleService(lc);
auto* timeSyncService = lifecycleService->CreateTimeSyncService();
// Set simulation step to a lambda
timeSyncService->SetSimulationStepHandler(
[](std::chrono::nanoseconds now, std::chrono::nanoseconds duration) {
// Do simulation computation at timepoint 'now'
}, 1ms
);
Retrieving the Current Time
After a successful startup according to the Lifecycle State Machine, the participant will enter the Running
state.
The participant can now access the current simulation time using the Now()
method which will be equal to the time transported in the last simulation step handler.
Asynchronous Step Handler
In special cases, it may be required to synchronize an application thread with the execution of the simulation step.
That is, the application wants to execute some code during a simulation step, but on a different thread than where the simulation step is executing.
To achieve this, use SetSimulationStepHandlerAsync()
to assign the simulation step function that is triggered when the virtual time advances, and CompleteSimulationStep()
to manually trigger the end of the simulation step and continue the simulation.
Note
See Blocking vs. Asynchronous Step Handler for more details and the differences between the handler modes.
API Reference
-
class ITimeSyncService
Public Types
-
using SimulationStepHandler = std::function<void(std::chrono::nanoseconds now, std::chrono::nanoseconds duration)>
Public Functions
-
virtual ~ITimeSyncService() = default
-
virtual void SetSimulationStepHandler(SimulationStepHandler task, std::chrono::nanoseconds initialStepSize) = 0
Set the task to be executed with each grant / tick.
Can be changed at runtime. Execution context depends on the run type.
Throwing an error inside the handler will cause a call to ReportError().
-
virtual void SetSimulationStepHandlerAsync(SimulationStepHandler task, std::chrono::nanoseconds initialStepSize) = 0
Set the task to be executed with each grant / tick.
Can be changed at runtime. Execution context depends on the run type. Execution will perform one simulation step at a time. CompleteSimulationStep is required to signal completion of the simulation step.
Throwing an error inside the handler will cause a call to ReportError().
-
virtual void CompleteSimulationStep() = 0
Signal that the current simulation task is finished and the next simulation step can be processed.
This method should only be used after calling SetSimulationStepHandlerAsync. Otherwise, undefined runtime behavior will result.
-
virtual auto Now() const -> std::chrono::nanoseconds = 0
Get the current simulation time.
-
using SimulationStepHandler = std::function<void(std::chrono::nanoseconds now, std::chrono::nanoseconds duration)>