# How the Parallel Module Works for Multi-Threaded Computations in Nelson

> Explore Nelson's parallel module for multi-threaded computations. Learn how its C++17 thread pool and Future objects enable asynchronous execution with MATLAB-compatible parfeval syntax.

- Repository: [The Nelson Programming Language/nelson](https://github.com/nelson-lang/nelson)
- Tags: internals
- Published: 2026-03-08

---

**Nelson's parallel module implements multi-threaded computations using a C++17 thread pool that executes functions asynchronously through Future objects, enabling MATLAB-compatible `parfeval` syntax for background task execution.**

The parallel module in Nelson provides asynchronous, multi-threaded evaluation of functions for the nelson-lang/nelson open-source interpreter. By leveraging a custom C++ thread pool and Future-based task management, this module enables users to offload computations to background threads while maintaining a MATLAB-compatible API.

## Core Architecture of the Parallel Module

### Thread-Pool Implementation with BS::pause_thread_pool

At the foundation lies a header-only C++ thread pool implementation located in [[`modules/parallel/src/include/BS_thread_pool.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/include/BS_thread_pool.hpp)](https://github.com/nelson-lang/nelson/blob/master/modules/parallel/src/include/BS_thread_pool.hpp). This file wraps Barak Shoshany's modern C++17/20 thread pool, providing the `BS::pause_thread_pool` class that Nelson uses for worker thread management.

The pool supports **pausing** and **unpausing** operations, which the Nelson runtime employs to temporarily halt background work while the interpreter executes critical sections or undergoes state changes.

### Singleton Background Pool Management

Nelson maintains a single global thread pool through the **BackgroundPoolObject** singleton, defined in [[`modules/parallel/src/include/BackgroundPoolObject.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/include/BackgroundPoolObject.hpp)](https://github.com/nelson-lang/nelson/blob/master/modules/parallel/src/include/BackgroundPoolObject.hpp) and implemented in [[`modules/parallel/src/cpp/BackgroundPoolObject.cpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/cpp/BackgroundPoolObject.cpp)](https://github.com/nelson-lang/nelson/blob/master/modules/parallel/src/cpp/BackgroundPoolObject.cpp).

Upon construction, this singleton creates a `pause_thread_pool` whose size is determined by `NelsonConfiguration::getMaxNumCompThreads()`, allowing users to configure thread count through Nelson's standard configuration mechanisms.

## How Asynchronous Task Execution Works

### Future Objects and State Management

Every asynchronous computation in Nelson is represented by a **Future** object. The base class `FutureObject` in [[`modules/parallel/src/include/FutureObject.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/include/FutureObject.hpp)](https://github.com/nelson-lang/nelson/blob/master/modules/parallel/src/include/FutureObject.hpp) stores:

- The function name and arguments
- The result vector
- Execution state (`QUEUED`, `RUNNING`, `FINISHED`, `CANCELLED`)
- Time stamps for creation and completion

For function evaluation specifically, Nelson uses `FevalFutureObject` ([[`modules/parallel/src/include/FevalFutureObject.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/include/FevalFutureObject.hpp)](https://github.com/nelson-lang/nelson/blob/master/modules/parallel/src/include/FevalFutureObject.hpp) and [[`modules/parallel/src/cpp/FevalFutureObject.cpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/cpp/FevalFutureObject.cpp)](https://github.com/nelson-lang/nelson/blob/master/modules/parallel/src/cpp/FevalFutureObject.cpp)), which knows how to execute a Nelson `FunctionDef` in the background.

### Task Submission via feval

The core mechanism for scheduling work resides in `BackgroundPoolObject::feval`. When you call `parfeval` from an .m script, it ultimately invokes this C++ method, which submits a lambda to the thread pool:

```cpp
// Excerpt from BackgroundPoolObject::feval
auto future = threadPool->submit_task(
    [retFuture, fptr, nLhs, argIn]() {
        retFuture->evaluateFunction(fptr, nLhs, argIn, true);
    });

```

The `submit_task` method belongs to `BS::pause_thread_pool` and enqueues the lambda for execution on a worker thread. The lambda captures a newly allocated `FevalFutureObject` along with the function pointer and arguments, executing `evaluateFunction` in the background.

### Global Future Queue Tracking

Every created future registers with the **FevalQueueObject** ([[`modules/parallel/src/include/FevalQueueObject.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/include/FevalQueueObject.hpp)](https://github.com/nelson-lang/nelson/blob/master/modules/parallel/src/include/FevalQueueObject.hpp) and [[`modules/parallel/src/cpp/FevalQueueObject.cpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/cpp/FevalQueueObject.cpp)](https://github.com/nelson-lang/nelson/blob/master/modules/parallel/src/cpp/FevalQueueObject.cpp)). This global queue allows the interpreter to:

- Query outstanding futures
- Cancel pending or running tasks
- Retrieve results through `fetchNext` or `fetchOutputs`

## MATLAB-Compatible API: parfeval and Background Pool

The parallel module exposes a MATLAB-compatible interface through built-in functions defined in `modules/parallel/builtin/include/*Builtin.hpp` (such as [`parfevalBuiltin.hpp`](https://github.com/nelson-lang/nelson/blob/main/parfevalBuiltin.hpp)). The `parfeval` function connects .m scripts to the C++ core:

```matlab
f = parfeval(pool, @myFunction, nLhs, arg1, arg2, ...);

```

Here, `pool` is a handle to the singleton background pool obtained via `backgroundPool`. The call returns a **Future** handle that supports:

- `fetchOutputs(f)` – Retrieve results (blocks until finished)
- `wait(f)` – Block until completion without retrieving results
- `cancel(f)` – Mark the future as cancelled
- `f.State` – Query current execution state

## Practical Examples

### Simple Asynchronous Call

This example demonstrates scheduling a function that sleeps for 2 seconds while the main thread continues working:

```matlab
% Create a reference to the global background pool
pool = backgroundPool;    % built-in handle

% Schedule a function that sleeps 2 seconds and returns the value 42
f = parfeval(pool, @() pause(2); 0, 42);   % 0 lhs because we just want the result

% Do other work while the background thread sleeps
disp('Main thread is busy...');
tic;
while ~strcmp(f.State, 'finished')
    pause(0.5);               % poll every 0.5 s
    fprintf('...still waiting (%.1f s elapsed)\n', toc);
end

% Retrieve the result (throws if the future failed)
result = fetchOutputs(f);
fprintf('Result from background thread: %g\n', result);

```

*Relevant sources*: `parfeval` → `BackgroundPoolObject::feval` (see the `submit_task` lambda), `FevalFutureObject` stores the result, `fetchOutputs` reads it.

### Parallel Array of Futures

Run multiple independent computations simultaneously and collect results:

```matlab
% Run three independent calls in parallel
pool = backgroundPool;
f(1) = parfeval(pool, @sin, 1, pi/6);
f(2) = parfeval(pool, @cos, 1, pi/6);
f(3) = parfeval(pool, @tan, 1, pi/6);

% Wait for all to finish (equivalent to MATLAB's wait for all)
wait(f);          % blocks until every future is FINISHED

% Collect results
s = fetchOutputs(f(1));
c = fetchOutputs(f(2));
t = fetchOutputs(f(3));
fprintf('sin=%.3f, cos=%.3f, tan=%.3f\n', s, c, t);

```

*Relevant sources*: `FevalQueueObject::add` (queues each future), `wait` implementation in [`Future_waitBuiltin.hpp`](https://github.com/nelson-lang/nelson/blob/main/Future_waitBuiltin.hpp) that repeatedly checks `future->state`.

### Canceling Long-Running Computations

Terminate background tasks that are no longer needed:

```matlab
pool = backgroundPool;
% Start a heavy loop that never ends unless cancelled
f = parfeval(pool, @() while true; pause(0.1); end, 0);

% Let it run for a second, then cancel
pause(1);
cancel(f);                 % marks the future as CANCELLED
% Fetch will now raise an exception
try
    fetchOutputs(f);
catch e
    disp(['Computation cancelled: ' e.message]);
end

```

*Relevant sources*: `FutureObject::cancel` (sets `state = CANCELLED`), `FevalFutureObject::evaluateFunction` checks `changeState` flag and aborts if cancelled.

## Key Source Files

The parallel module spans several critical files in the `nelson-lang/nelson` repository:

- **[`modules/parallel/src/include/BS_thread_pool.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/include/BS_thread_pool.hpp)** – Header-only C++ thread pool (`BS::pause_thread_pool`) providing the core worker thread management with pause/unpause capabilities.

- **[`modules/parallel/src/include/BackgroundPoolObject.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/include/BackgroundPoolObject.hpp)** and **[`modules/parallel/src/cpp/BackgroundPoolObject.cpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/cpp/BackgroundPoolObject.cpp)** – Singleton managing the global thread pool instance and exposing the `feval` method for task submission.

- **[`modules/parallel/src/include/FutureObject.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/include/FutureObject.hpp)** – Base class defining the Future interface, execution states (`QUEUED`, `RUNNING`, `FINISHED`, `CANCELLED`), and result storage.

- **[`modules/parallel/src/include/FevalFutureObject.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/include/FevalFutureObject.hpp)** and **[`modules/parallel/src/cpp/FevalFutureObject.cpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/cpp/FevalFutureObject.cpp)** – Specialized Future implementation that executes Nelson `FunctionDef` objects in background threads.

- **[`modules/parallel/src/include/FevalQueueObject.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/include/FevalQueueObject.hpp)** and **[`modules/parallel/src/cpp/FevalQueueObject.cpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/cpp/FevalQueueObject.cpp)** – Global registry tracking all active futures, enabling `wait`, `cancel`, and queue inspection operations.

- **[`modules/parallel/src/include/ParallelEvaluator.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/include/ParallelEvaluator.hpp)** and **[`modules/parallel/src/cpp/ParallelEvaluator.cpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/cpp/ParallelEvaluator.cpp)** – Factory for creating per-task `Evaluator` instances that run in worker threads.

- **`modules/parallel/builtin/include/*Builtin.hpp`** (e.g., [`parfevalBuiltin.hpp`](https://github.com/nelson-lang/nelson/blob/main/parfevalBuiltin.hpp)) – Built-in function declarations connecting the Nelson language syntax to the C++ parallel core.

## Summary

- **Nelson's parallel module** utilizes a header-only C++17 thread pool (`BS::pause_thread_pool`) defined in [`BS_thread_pool.hpp`](https://github.com/nelson-lang/nelson/blob/main/BS_thread_pool.hpp) to manage worker threads.
- A **singleton BackgroundPoolObject** maintains the global thread pool instance, sized according to `NelsonConfiguration::getMaxNumCompThreads()`.
- **Future objects** (`FevalFutureObject`) encapsulate asynchronous computations, tracking states from `QUEUED` through `FINISHED` or `CANCELLED`.
- Tasks are submitted via **lambda functions** to the thread pool through `BackgroundPoolObject::feval`, which captures the future and function arguments for background execution.
- The **FevalQueueObject** maintains a global registry of all futures, supporting MATLAB-compatible operations like `wait`, `cancel`, and `fetchOutputs`.
- The module supports **pausing and resetting** the thread pool to handle interpreter critical sections safely.

## Frequently Asked Questions

### What thread pool library does Nelson use for parallel computations?

Nelson uses a header-only C++ thread pool implementation located in [`modules/parallel/src/include/BS_thread_pool.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/parallel/src/include/BS_thread_pool.hpp). This is based on Barak Shoshany's modern C++17/20 thread pool and provides the `BS::pause_thread_pool` class with support for pausing, unpausing, and dynamic resizing of worker threads.

### How does Nelson handle thread safety during interpreter critical sections?

The parallel module implements a pause mechanism through `BS::pause_thread_pool`. When the interpreter enters a critical section or requires temporary thread safety, it calls `threadPool->pause()` to halt background task processing. Once the critical section completes, `threadPool->unpause()` resumes normal operation. This approach avoids complex locking by temporarily stopping worker threads rather than implementing fine-grained synchronization.

### Can I cancel a computation that is already running in the background?

Yes, the parallel module supports cancellation through the `cancel` function. When invoked, it calls `FutureObject::cancel` which sets the future's state to `CANCELLED`. The `FevalFutureObject::evaluateFunction` method periodically checks the `changeState` flag and aborts execution if cancellation is detected, preventing wasted CPU cycles on obsolete computations.

### How is the number of parallel threads configured in Nelson?

The thread pool size is determined by `NelsonConfiguration::getMaxNumCompThreads()`, which reads user configuration settings. The `BackgroundPoolObject` singleton initializes the `pause_thread_pool` with this size during construction. Users can also resize the pool dynamically through `resetThreadPool`, which invokes `threadPool->reset(newSize)` to adjust the number of worker threads without restarting the interpreter.