# How to Implement Conditional Execution Flows in CGraph Pipelines

> Learn to implement conditional execution flows in CGraph pipelines using GCondition and GMultiCondition. Dynamically choose execution paths for efficient pipeline logic.

- Repository: [Chunel/cgraph](https://github.com/chunelfeng/cgraph)
- Tags: how-to-guide
- Published: 2026-02-27

---

**CGraph implements conditional execution flows through the `GCondition` abstraction, which uses a virtual `choose()` method to select specific child elements at runtime, while `GMultiCondition` provides serial and parallel execution modes for running multiple branches.**

CGraph is a high-performance C++ task graph framework that enables dynamic pipeline control through condition groups. The primary mechanism for implementing conditional execution flows in CGraph pipelines involves inheriting from `GCondition` and overriding the selection logic to determine which child nodes execute. This approach supports data-driven branching, feature toggles, and error handling within complex computational graphs.

## Understanding the GCondition Abstraction

### Core Architecture and the choose() Method

At the heart of conditional execution lies `GCondition`, an abstract class defined in [`src/GraphCtrl/GraphElement/GGroup/GCondition/GCondition.h`](https://github.com/chunelfeng/cgraph/blob/main/src/GraphCtrl/GraphElement/GGroup/GCondition/GCondition.h). This class inherits from `GGroup` and requires implementations to override the pure-virtual method:

```cpp
virtual CIndex choose() = 0;

```

The `choose()` method returns the **zero-based index** of the child element to execute. Returning `-1` signals the framework to execute the last element in the group. When the pipeline runs, `GCondition::run()` queries `choose()` and dispatches execution to the selected child only.

### Source File Locations

The condition group implementation spans several key files in the CGraph repository:

- [`src/GraphCtrl/GraphElement/GGroup/GCondition/GCondition.h`](https://github.com/chunelfeng/cgraph/blob/main/src/GraphCtrl/GraphElement/GGroup/GCondition/GCondition.h) — Defines the abstract base class and `choose()` contract
- [`src/GraphCtrl/GraphElement/GGroup/GCondition/GMultiCondition.h`](https://github.com/chunelfeng/cgraph/blob/main/src/GraphCtrl/GraphElement/GGroup/GCondition/GMultiCondition.h) — Template implementation for serial and parallel multi-condition groups
- [`tutorial/MyGCondition/MyCondition.h`](https://github.com/chunelfeng/cgraph/blob/main/tutorial/MyGCondition/MyCondition.h) — Example user-defined condition selecting a specific child index
- [`tutorial/T21-MultiCondition.cpp`](https://github.com/chunelfeng/cgraph/blob/main/tutorial/T21-MultiCondition.cpp) — Demonstrates both serial and parallel execution patterns
- [`tutorial/T06-Condition.cpp`](https://github.com/chunelfeng/cgraph/blob/main/tutorial/T06-Condition.cpp) — Basic condition usage without multi-condition wrappers

## Implementing Single-Branch Selection

### Creating a Custom Condition Class

To implement conditional execution flows that select a single branch, derive from `GCondition` and implement the selection logic. The tutorial file [`tutorial/MyGCondition/MyCondition.h`](https://github.com/chunelfeng/cgraph/blob/main/tutorial/MyGCondition/MyCondition.h) provides a minimal example:

```cpp
// MyCondition.h
#include "CGraph.h"

class MyCondition : public CGraph::GCondition {
public:
    // Always select the second child (index 1)
    CIndex choose() override { return 1; }
};

```

For dynamic branching based on runtime state, inspect internal flags or pipeline parameters:

```cpp
class SwitchCondition : public CGraph::GCondition {
public:
    CIndex choose() override {
        // Return 0 for success path, 1 for failure path
        return validationPassed ? 0 : 1;
    }
    
private:
    bool validationPassed = false; // Set during previous node execution
};

```

### Registering Conditions in the Pipeline

Condition groups are created and registered similarly to standard nodes. Use `createGGroup` to instantiate the condition and `registerGGroup` to add it to the pipeline:

```cpp
// pipeline_example.cpp
#include "MyCondition.h"

void example_simple_condition() {
    auto pipeline = CGraph::GPipelineFactory::create();

    // Create a condition group with two alternative nodes
    auto condGroup = pipeline->createGGroup<CGraph::GCondition>({
        pipeline->createGNode<NodeA>(CGraph::GNodeInfo("nodeA")),
        pipeline->createGNode<NodeB>(CGraph::GNodeInfo("nodeB"))
    });

    // Register with no predecessors
    CGraph::CStatus status = pipeline->registerGGroup(&condGroup, {}, "myCond");
    if (!status.isOK()) return;

    pipeline->process();
    CGraph::GPipelineFactory::remove(pipeline);
}

```

## Multi-Condition Execution Patterns

### Serial Execution with GMultiCondition

When you need to execute multiple child elements in a specific order, use `GMultiCondition` with the `SERIAL` template parameter. This class is defined in [`src/GraphCtrl/GraphElement/GGroup/GCondition/GMultiCondition.h`](https://github.com/chunelfeng/cgraph/blob/main/src/GraphCtrl/GraphElement/GGroup/GCondition/GMultiCondition.h) and overrides `choose()` to always return `-1`, ensuring all children run.

The `serialRun()` method iterates through children sequentially:

```cpp
// T21-MultiCondition.cpp excerpt
void tutorial_serial_condition() {
    auto pipeline = CGraph::GPipelineFactory::create();

    // SERIAL group: children execute one after another
    auto serialGrp = pipeline->createGGroup<
        CGraph::GMultiCondition<CGraph::GMultiConditionType::SERIAL>
    >({
        pipeline->createGNode<PreprocessNode>(CGraph::GNodeInfo("preprocess")),
        pipeline->createGNode<ValidateNode>(CGraph::GNodeInfo("validate")),
        pipeline->createGNode<TransformNode>(CGraph::GNodeInfo("transform"))
    });

    CGraph::GElementPtr prev = nullptr;
    pipeline->registerGElement<StartNode>(&prev, {}, "start");
    pipeline->registerGGroup(&serialGrp, {prev}, "serialGroup");
    
    pipeline->process();
    CGraph::GPipelineFactory::remove(pipeline);
}

```

### Parallel Execution with GMultiCondition

For independent operations that can run simultaneously, use `GMultiCondition` with the `PARALLEL` template parameter. The `parallelRun()` method dispatches each child to the CGraph thread pool:

```cpp
// Parallel execution example
void tutorial_parallel_condition() {
    auto pipeline = CGraph::GPipelineFactory::create();

    auto parallelGrp = pipeline->createGGroup<
        CGraph::GMultiCondition<CGraph::GMultiConditionType::PARALLEL>
    >({
        pipeline->createGNode<IOReadNode>(CGraph::GNodeInfo("ioRead")),
        pipeline->createGNode<NetworkFetchNode>(CGraph::GNodeInfo("networkFetch")),
        pipeline->createGNode<CacheLoadNode>(CGraph::GNodeInfo("cacheLoad"))
    });

    // All three nodes start simultaneously
    pipeline->registerGGroup(&parallelGrp, {}, "parallelGroup");
    pipeline->process();
    CGraph::GPipelineFactory::remove(pipeline);
}

```

Execution continues only after **all** parallel children complete. This pattern maximizes throughput for I/O-bound or computationally independent tasks.

## Practical Use Cases for Conditional Flows

### Dynamic Branching Based on Runtime Data

Conditional execution flows enable data-driven pipeline routing. Implement `choose()` to inspect parameters set by previous nodes:

```cpp
class DataDrivenCondition : public CGraph::GCondition {
public:
    CStatus init() override {
        // Retrieve parameter from previous execution
        auto* param = CGraph::GParamManager::get()->get<PipelineParam>("config");
        threshold = param->confidenceThreshold;
        return CStatus();
    }
    
    CIndex choose() override {
        // Route to high-precision path (index 0) or fast path (index 1)
        return (threshold > 0.9) ? 0 : 1;
    }
    
private:
    float threshold = 0.0f;
};

```

This pattern supports **A/B testing**, **quality-of-service routing**, and **adaptive algorithms** where the execution path depends on intermediate results.

### Error Handling and Fallback Paths

Use `GCondition` to implement circuit-breaker patterns or fallback chains. Structure the condition with multiple children representing primary, secondary, and error-handling nodes:

```cpp
class ResilientCondition : public CGraph::GCondition {
public:
    CIndex choose() override {
        if (primarySuccess) return 0;  // Primary service
        if (secondaryAvailable) return 1;  // Backup service
        return 2;  // Error handler (last child)
    }
    
    // Set by previous nodes via shared state
    bool primarySuccess = false;
    bool secondaryAvailable = false;
};

```

Register the children in order: primary node, fallback node, and error handler. The `choose()` method acts as a decision tree, ensuring the pipeline degrades gracefully rather than failing entirely.

## Summary

- **GCondition** provides the foundation for conditional execution flows in CGraph pipelines through the pure-virtual `choose()` method defined in [`src/GraphCtrl/GraphElement/GGroup/GCondition/GCondition.h`](https://github.com/chunelfeng/cgraph/blob/main/src/GraphCtrl/GraphElement/GGroup/GCondition/GCondition.h).
- **Single-branch selection** requires deriving from `GCondition` and returning the target child index from `choose()`, enabling dynamic routing based on runtime state.
- **GMultiCondition** extends this model to execute all children either serially (`GMultiConditionType::SERIAL`) or in parallel (`GMultiConditionType::PARALLEL`), with implementation details in [`src/GraphCtrl/GraphElement/GGroup/GCondition/GMultiCondition.h`](https://github.com/chunelfeng/cgraph/blob/main/src/GraphCtrl/GraphElement/GGroup/GCondition/GMultiCondition.h).
- **Registration** follows the standard CGraph pattern using `createGGroup()` and `registerGGroup()`, treating condition groups similarly to standard nodes while maintaining dependency relationships.
- **Practical applications** include data-driven branching, A/B testing, circuit-breaker patterns, and resilient fallback chains.

## Frequently Asked Questions

### How does GCondition decide which child node to execute?

The `GCondition` class delegates this decision to the pure-virtual `choose()` method, which must be implemented by derived classes. This method returns a `CIndex` (integer) representing the zero-based position of the child to execute, or `-1` to select the last child. When the pipeline runs, `GCondition::run()` queries this method and dispatches execution only to the selected child, skipping all others.

### What is the difference between GCondition and GMultiCondition?

`GCondition` is an abstract base class designed for **selective execution**—it runs exactly one child determined by the `choose()` implementation. `GMultiCondition` is a concrete template class derived from `GCondition` that overrides `choose()` to always return `-1`, causing it to execute **all** children. The template parameter `GMultiConditionType` controls whether children run sequentially (`SERIAL`) or concurrently (`PARALLEL`), making `GMultiCondition` suitable for grouped execution rather than branching logic.

### Can condition groups be nested within other groups or connected to standard nodes?

Yes, condition groups integrate seamlessly with standard CGraph pipelines. You register them using `registerGGroup()`, specifying predecessor elements (which can be standard nodes or other groups) in the dependency list. The condition group itself can also serve as a dependency for subsequent nodes. This allows complex hierarchies where a `GCondition` selects between sub-pipelines, or where a `GMultiCondition` encapsulates a sequence of operations treated as a single logical unit within the larger graph.