Operator Lifecycle
🚧 Documentation is under development
The Holoscan SDK guide is currently under active development. Some sections may be incomplete or change without notice.
Questions? Contact RidgeRun or email to support@ridgerun.com.
-
Overview
-
Build, Run, and Validate
-
Core Concepts
-
Operators and Graphs
-
Tensor Data and Memory
-
Interprocess Communication
-
-
Application and Operator Development
- Building an HSDK Application
- Writing a Minimal Operator
- Typed Parameters and Configuration
- Reading, Writing, and Forwarding Data
- Writing Tensor Operators
- Complete Operator Patterns
- Authoring Runtime Behavior
- Runtime Parameter Updates
- Lifecycle Callbacks and Restart Control
- Performance and Debugging
- SDK Source Map
-
Operator Reference
-
Core Operators
-
Holoscan Camera
-
Holoscan RidgeRun
- Overview
- Build and Installation
- ArgusCameraOp
- V4L2SourceOp
- V4L2UserPtrSourceOp
- BgraToPlanarTensorOp
- RawBayerToBgraOp
- RawBayerToYoloTensorOp
- YuyvToBgraOp
- TensorRtInferenceOp
- DrmDisplayOp
- DrmBgraDisplayOp
- X11DisplayOp
- CudaCompositorOp
- DepthColorizerOp
- FakesinkOp
- FrameSkipperOp
- InterprocessSrcOp
- TestPatternOp
-
-
Migration from Holoscan 4.x
-
Examples
-
Core
-
Holoscan Camera
-
Holoscan RidgeRun
-
-
Benchmark and Use Cases
-
Holoscan vs GStreamer
- Overview
-
Capture and Display
-
Capture and Inference
- Compare the workloads
- Implemented Applications
- Framework Selection
- Interprocess
-
Operator Lifecycle
An operator receives data, performs one step of application work, and publishes a result. Its class describes the interface during graph construction and performs the work after the graph starts.
Keep the two moments separate:
- Authoring declares ports, parameters, and execution rules.
- Running selects input data, calls the operator, and manages its resources.
See where each method runs
| Phase | What happens | Common code |
|---|---|---|
| Authoring | The application creates the operator and connects it to other operators. | Constructor and setup()
|
| Compilation | Holoscan checks the declarations and creates an ExecutionPlan. |
contract() and graph connections
|
| Startup | The run prepares the resources needed by the active graph. | start() or a lifecycle callback
|
| Processing | The runtime selects the inputs for one activation and calls compute(). |
Read inputs, do the work, and publish outputs |
| Shutdown | The run stops new activations and releases resources. | stop() and cleanup callbacks
|
A constructor, setup(), or contract() describes the operator. Avoid opening devices, starting worker threads, or allocating resources that belong to one run in those methods. Put that work in start(), compute(), or stop() according to its lifetime.
Build a small operator
The following operator reads one integer, doubles it, and publishes the result. It shows the usual order: declare an Input<T> and an Output<T>, select one input per activation, read it with receive_data(), and publish with emit().
#include <cstdint>
#include <utility>
#include <holoscan/core/execution_context.hpp>
#include <holoscan/core/operator.hpp>
#include <holoscan/core/operator_spec.hpp>
#include <holoscan/core/port.hpp>
#include <holoscan/core/temporal_contract.hpp>
class DoubleOp final : public holoscan::Operator<> {
public:
holoscan::Input<std::int32_t> input;
holoscan::Output<std::int32_t> output;
void setup(holoscan::OperatorSpec& spec) override {
spec.input(input, "input");
spec.output(output, "output");
}
holoscan::Contract contract() const override {
holoscan::Contract result;
result.trigger(holoscan::OnEach{input});
return result;
}
holoscan::expected<void, holoscan::Error> compute(
holoscan::ExecutionContext&) override {
auto value = input.receive_data();
if (!value) {
return holoscan::make_unexpected(std::move(value).error());
}
return output.emit(*value * 2);
}
};
Input<T> and Output<T> declare the value types at the operator boundary. OnEach tells the runtime to activate the operator when a new value is available on input. The next page explains how values, samples, and payload types move through those ports.
Choose the lifecycle style
Use start() and stop() for simple initialization and cleanup. Use staged lifecycle callbacks when startup needs separate phases such as discovery, allocation, warm-up, or device binding. Register them through spec.lifecycle().
Keep lifecycle code focused on the resources owned by the operator. A restart can run startup and cleanup again, so release the resources associated with the active run before creating them again.
Continue the flow
- Ports, Samples, and Payload Types explains the data exchanged by the ports.
- Temporal Contracts and Input Selection explains when an operator is activated and which inputs it receives.
- Building Graphs and Queue Policies explains how operators are connected and buffered.
- Writing a Minimal Operator turns this class pattern into a complete application.