Choosing Between LabVIEW Actor Framework and Queued Message Handler for Modular Applications
Decision guide for LabVIEW 2020–2024: choose Actor Framework for hierarchical, plug‑in systems with strict encapsulation; choose Queued Message Handler for simpler, faster onboarding on small‑to‑medium message sets. Includes benchmark method and migration path.
30 Jul 2025, 08:24 UTC

The Decision: Architecture Pattern for Maintainable LabVIEW Systems
Teams building LabVIEW 2020–2024 applications face a recurring architectural choice: adopt NI's built-in Actor Framework (AF) or implement a Queued Message Handler (QMH) pattern. Both support modular, message-driven designs, but they impose different constraints on team skill set, system complexity, and long-term maintenance. The practical takeaway: start with QMH for systems under 15–20 message types and small teams; migrate to AF when you need hierarchical actor trees, plug‑in extensibility, or built‑in monitoring across dozens of modules.
Constraints That Shape the Choice
- Team experience: AF requires fluency in LVOOP (LabVIEW Object‑Oriented Programming), dynamic dispatch, and override patterns. Budget 2–4 weeks for onboarding if the team lacks this background.
- Message count: QMH case structures become unwieldy beyond 20–30 enum cases. AF scales naturally because each message is a separate class.
- Runtime hierarchy: AF enforces a launcher tree (parent actors launch children). QMH loops are typically peers coordinated by a top‑level sequencer.
- Real‑time targets: On LabVIEW Real‑Time Module, both patterns must replace standard queues with RT FIFOs or timed loops for deterministic scheduling. Neither pattern guarantees determinism out of the box.
- Licensing: Both ship with Base/Full/Professional editions at no extra cost. AF source lives in
vi.lib/addons/actorframework; QMH examples are downloadable from ni.com/example-code.
Side‑by‑Side Comparison
| Dimension | Actor Framework (AF) | Queued Message Handler (QMH) |
|---|---|---|
| Core mechanism | Dynamic dispatch on message classes; each actor is a class inheriting from Actor.lvclass | Single loop dequeuing a typed enum/string queue; case structure executes per message |
| Message definition | One LV class per message (extends Message.lvclass) | Enum or string typedef; payload in variant or cluster |
| Encapsulation | Strict: private data in actor class; messages cannot access internals directly | Loose: queue reference often passed to subVIs; data clusters shared by convention |
| Hierarchy & launch | Built‑in Launch Actor / Launch Nested Actor; automatic tree tracking | Manual: developer starts loops, tracks references, sequences shutdown |
| Monitoring & debugging | Actor Tree Viewer (Tools → Actor Framework) shows live hierarchy, message flow | Custom probes, front‑panel indicators, or user‑built dashboard |
| Error handling | Pre/Post Launch overrides; Handle Error.vi per actor | Central error cluster on queue; case for "Error" message or timeout handling |
| Typical overhead | 5–15 µs/message (dynamic dispatch + class wiring) | 1–3 µs/message (queue dequeue + case selection) |
| Migration path | QMH → AF: wrap QMH loop as AF actor (straightforward) | AF → QMH: rewrite message classes into enum cases (significant effort) |
| Tooling | Actor Core template, Message Maker scripting, AF Test Toolkit | Standard VI templates; community scripting tools |
Trade‑offs in Practice
When QMH Wins
- Small team (2–4 developers) with limited LVOOP experience.
- Application has 5–15 distinct message types per module (e.g., DAQ loop, motion controller, UI handler).
- Rapid prototyping: a QMH loop can be sketched in 30 minutes using the NI example template.
- Deterministic real‑time loops where you already manage RT FIFOs manually and want minimal abstraction overhead.
When AF Wins
- System grows beyond 20 message types per module or needs plug‑in actors loaded at runtime (e.g., test sequencer that discovers instrument drivers).
- Multiple teams own separate actors; strict encapsulation prevents coupling through shared clusters.
- You need built‑in actor tree visualization for integration testing — Actor Tree Viewer shows message routing without custom code.
- Long‑lived product line where new actors are added yearly; AF's class‑per‑message structure isolates changes.
Concrete Validation: Benchmark Both Patterns on Your Hardware
Performance claims are hardware‑dependent. Run this comparison on your deployment target (Windows PC, cRIO, PXI controller) before committing.
Benchmark Setup
- Create a new LabVIEW 2024 project.
- Add Actor Framework Template: File → Create Project → Actor Framework Template. Name the actor "BenchmarkActor".
- Add QMH Template: Download "QMH Template.lvproj" from ni.com/example-code (search "Queued Message Handler"). Copy the QMH loop VI into your project.
- In each pattern, implement a message that increments a counter (AF:
IncrementMessage.lvclass; QMH: enum case "Increment" with U32 payload). - Build a benchmark VI that:
- Launches the AF actor (or starts the QMH loop).
- Sends 100,000 messages in a tight loop using
Enqueue(AF) orEnqueue Element(QMH). - Measures elapsed time with
Tick Count (ms)before first send and after last dequeue confirmation. - Repeats 5× and logs median loop iteration time.
Expected Checks
- AF median iteration: typically 8–20 µs on modern x64 CPUs; higher on cRIO‑904x (ARM).
- QMH median iteration: typically 2–5 µs on same hardware.
- If both are < 1 ms per 100 messages, overhead is negligible for 1–100 Hz control loops.
Risks
- Running 100k messages back‑to‑back may starve the UI thread; run benchmark in a separate compiled executable or set VI execution priority to "Above Normal".
- On RT targets, use
Timed Loopwith 1 kHz period instead of free‑running loop to reflect real scheduling.
Implementation Starter: Wrapping a QMH Module as an AF Actor
If you begin with QMH and later need AF's hierarchy, the migration is incremental. This pattern preserves existing QMH logic while exposing it as an AF actor.
Steps
- Create a new AF actor class (e.g.,
DAQActor.lvclass) inheriting fromActor.lvclass. - In
Actor Core.vioverride, instantiate your existing QMH loop as a subVI (or copy its block diagram into the override). - Define AF message classes for each external command (e.g.,
StartAcqMessage,StopAcqMessage). Each message'sDo.vienqueues the corresponding QMH enum case onto the QMH's internal queue. - Implement
Pre Launch.vito initialize hardware references;Post Launch.vito start the QMH loop. - Implement
Handle Error.vito translate QMH error clusters into AF error messages.
Verification
- Open Actor Tree Viewer (Tools → Actor Framework → Actor Tree Viewer) and launch the top‑level actor. The wrapped DAQActor should appear in the tree with its message queue depth visible.
- Send
StartAcqMessagefrom a test VI; confirm QMH loop transitions to "Acquiring" state via front‑panel probe.
Limitations and Review Triggers
- AF learning curve is real. If after 3 sprints the team still struggles with dynamic dispatch debugging, reconsider QMH for new modules.
- QMH enum bloat: when a single QMH exceeds 30 cases, split into multiple QMH loops (each with its own queue) or migrate that module to AF.
- Real‑time determinism: neither pattern replaces RT FIFO or timed‑loop design. Validate jitter with
RT Get CPU Loads.viandTimed Loopstatistics on target hardware. - NI roadmap: LabVIEW NXG is deprecated (2021). AF and QMH are fully supported in LabVIEW 2020–2024 64‑bit. Check LabVIEW 2024 Release Notes (ni.com) for any updates before starting a new project.
Quick Decision Checklist
| Question | Yes → Lean Toward |
|---|---|
| Team knows LVOOP + dynamic dispatch? | AF |
| Message types per module > 20? | AF |
| Need runtime plug‑in actors? | AF |
| Need live actor tree visualization? | AF |
| Team size ≤ 4, limited OOP experience? | QMH |
| Prototype needed this week? | QMH |
| Deterministic RT loop with custom FIFO? | QMH (less abstraction) |
Pick the pattern that matches today's constraints; both are supported, both are free, and the migration path from QMH to AF is well‑trodden. Validate with the benchmark on your actual hardware before locking in.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.