Source Deep Dive: sc_spawn and Dynamic Processes
How dynamic processes are created, configured, named, made sensitive, and reviewed safely.
How to Read This Lesson
Most SystemC designs should create their structure during elaboration. Dynamic processes are the exception you use when the model really needs runtime-created behavior. This lesson teaches the power and the caution sign together.
Source and LRM Trail
Use Docs/LRMs/SystemC_LRM_1666-2023.pdf for process creation and simulation phase rules. In source, inspect .codex-src/systemc/src/sysc/kernel/sc_spawn.*, sc_spawn_options.*, sc_process.*, sc_method_process.*, and sc_thread_process.*.
Static Process First
Prefer this when possible:
SC_CTOR(Top) {
SC_THREAD(worker);
}The kernel sees the process during elaboration. The hierarchy is stable. Debugging is easier.
Dynamic spawning is for cases where process count or behavior is not naturally known until runtime:
- modeling dynamically created software tasks
- testbench workers created by a scenario
- protocol monitors attached after configuration
- temporary timeout watchers
Minimal Dynamic Spawn
#include <systemc>
using namespace sc_core;
SC_MODULE(Spawner) {
SC_CTOR(Spawner) {
SC_THREAD(run);
}
void run() {
sc_spawn_options opt;
opt.spawn_method();
opt.dont_initialize();
sc_event kick;
opt.set_sensitivity(&kick);
sc_spawn([&] {
std::cout << "dynamic method at " << sc_time_stamp() << "\n";
}, "dynamic_method", &opt);
kick.notify(SC_ZERO_TIME);
wait(SC_ZERO_TIME);
}
};This is not a recommended production pattern because the lambda captures a local event by reference. It is shown to make the mechanics visible. In production, make sure captured objects outlive the spawned process.
How the Source Makes This Work
sc_spawn_options describes what kind of process should be created:
- method or thread
- initialization behavior
- static sensitivity
- stack size or process control options where supported
sc_spawn then creates the corresponding process object and registers it with the current simulation context. After that, the dynamic process participates in the same runnable queues, waits, resets, and events as static processes.
That is the key idea: dynamic process creation changes when a process enters the kernel, not the fundamental scheduler semantics.
Lifetime Trap
Dynamic processes often capture C++ objects. The kernel can keep the process alive longer than the stack frame that created it.
Risky:
void launch() {
int local = 42;
sc_spawn([&] { std::cout << local << "\n"; });
}Safer:
auto value = std::make_shared<int>(42);
sc_spawn([value] { std::cout << *value << "\n"; });For models that need strict lifetime control, prefer owning spawned state in an sc_module member or a dedicated object with clear shutdown rules.
Review Checklist
- Why can this not be a static
SC_THREADorSC_METHOD? - Does every captured object outlive the spawned process?
- Is the process name stable and useful in reports?
- Is sensitivity configured explicitly?
- Is cleanup or termination behavior documented?
- Does the design avoid creating unbounded numbers of processes?
Comments and Corrections