Single-header, cross-platform C++11 library for managing concurrent task execution.
This repository contains source code developed as part of my Bachelor's Thesis (TFG):
-
Bachelor's Thesis URL: https://hdl.handle.net/2117/439429
-
Video Showcase: https://youtu.be/A4NfI6ALey8
-
Nous Engine Repository: https://github.com/francesctr4/Nous-Engine
-
Multithreading Library: https://github.com/francesctr4/NOUS_Multithreading.h
Author: Francesc Teruel Rodriguez (francesctr4 on GitHub)
Created: 11/07/2025
Version: 1.0
License: CC-BY-NC-SA License
Attribution-NonCommercial-ShareAlike 4.0 International
Copyright (©) 2025 Francesc Teruel Rodríguez
Pull requests are welcome! If you'd like to suggest improvements, add features, or report issues, feel free to open a GitHub issue or PR.
- ISO C++11 Standard (compile with
/std:c++11or-std=c++11) or newer
-
Download or copy the file
NOUS_Multithreading.hinto your project directory and add it to the project. -
Include the header in your source files:
#include "NOUS_Multithreading.h". -
Refer to the usage examples and API documentation provided to start using the job system into your application.
- Begin by calling RegisterMainThread() to retrieve and store information about the main thread.
- Create and configure an instance of the NOUS_JobSystem, typically as a pointer. If no thread count is specified during initialization, the system will automatically use the maximum number of hardware threads minus one, reserving one for the main thread.
- Once the job system is initialized, jobs can be submitted using the SubmitJob() function. Submitted jobs will be automatically queued, managed, and executed by the available worker threads.
- Before shutting down the system, it is recommended to explicitly call WaitForPendingJobs() to ensure all jobs have completed. While this step is already handled in the job system’s destructor, doing it manually is considered good practice for clarity and control.
- After all jobs have been processed, destroy the job system instance and call UnregisterMainThread() to clean up the main thread information.
#include "NOUS_Multithreading.h"
int main(int argc, char** argv)
{
NOUS_Multithreading::RegisterMainThread();
// Create the job system dynamically (using hardware concurrency)
NOUS_Multithreading::NOUS_JobSystem* jobSystem = new NOUS_Multithreading::NOUS_JobSystem();
// Submit jobs
jobSystem->SubmitJob([]() { /* task 1 */ }, "Task1");
jobSystem->SubmitJob([]() { /* task 2 */ }, "Task2");
// Wait for completion
jobSystem->WaitForPendingJobs();
// Optional debug output
NOUS_Multithreading::JobSystemDebugInfo(*jobSystem);
// Clean up when done
delete jobSystem;
NOUS_Multithreading::UnregisterMainThread();
return 0;
}
Represents an individual executable task with a name and function.
Creates a new job with a given name and function.
- Parameters:
name— A string identifier for the job (used for debugging/logging).func— The function to execute when the job runs.
Executes the job's stored function.
Returns the name identifier of the job.
A wrapper around std::thread with additional metadata for job execution, tracking, and debug support.
Initializes a thread object with default values. Does not start the thread automatically.
Destructor. Automatically joins the thread if it is still running.
Starts the thread with the specified function.
- Parameters:
func— The function to be executed on the thread.
- Note: Does nothing if the thread is already running.
Joins the thread if it's joinable and marks it as no longer running.
Sets a name for the thread (for debugging purposes).
Returns the thread's name.
Sets the current state (READY, RUNNING) of the thread.
Gets the current thread state.
Assigns the job currently running on the thread.
Returns a pointer to the currently running job, or nullptr.
Returns true if the thread is still active.
Returns the numeric ID of the thread.
Starts a timer to track how long the thread runs its current job.
Stops the timer after job execution ends.
Returns the execution duration in milliseconds.
If the timer is still running, returns the current elapsed time.
Manually sets a thread ID using the hash of the given std::thread::id.
Generates a hashed uint16_t ID from a given thread ID.
Converts a ThreadState enum to a string representation (READY, RUNNING, or UNKNOWN).
Pauses the current thread for the specified number of milliseconds.
Manages a pool of worker threads and distributes jobs among them.
Constructs a new thread pool with a specified number of worker threads.
- Parameters:
numThreads— Number of worker threads to initialize.
- Note: Marked
explicitto prevent accidental implicit conversions. - Behavior: Spawns
numThreadsand assigns each a worker loop.
Adds a job to the internal queue and notifies a waiting worker thread.
- Parameters:
job— Pointer to the job to be executed.
Gracefully shuts down the thread pool.
- Description:
- Waits for all jobs to finish.
- Deletes all remaining queued jobs.
- Joins and destroys all worker threads.
- Usage: Should be called manually if early shutdown is needed (automatically called in destructor).
Returns a reference to the internal vector of worker threads.
- Returns:
std::vectorof pointers toNOUS_Thread.
Returns a reference to the internal job queue.
- Returns:
std::queueof pendingNOUS_Job*tasks.
High-level interface for job submission and management.
Creates a new job system with a configurable number of worker threads.
- Parameters:
size— Number of threads in the thread pool.
If omitted, defaults toc_MAX_HARDWARE_THREADS.
- Note: If
sizeis0, jobs will execute sequentially on the main thread.
Submits a job to the thread pool to be executed by an available worker thread.
- Parameters:
userJob— The function (job) to execute.jobName— (Optional) A string identifier for the job.
- Note: If no worker threads are present, the job is executed immediately on the main thread.
Blocks the calling thread until all submitted jobs are completed.
Resizes the thread pool to a new number of worker threads.
- Parameters:
newSize— New number of worker threads.
- Note: Waits for all current jobs to finish before resizing.
- Note: If
newSizeis0, the system switches to single-threaded mode.
Returns a reference to the internal NOUS_ThreadPool used by the job system.
Returns the number of pending, unprocessed jobs still in the system.
Initializes the main thread tracking.
- Description: Registers the main thread as a
NOUS_Threadinstance for timing and debug purposes. - Note: Must be paired with
UnregisterMainThread()to prevent memory leaks.
Cleans up the main thread instance.
- Description: Deletes the registered main thread if it exists.
- Note: Should be called during application shutdown.
Retrieves the registered main thread.
- Returns: A pointer to the
NOUS_Threadrepresenting the main thread. Returnsnullptrif not registered.
Prints job system diagnostics to the console.
- Parameters:
system– A reference to the activeNOUS_JobSysteminstance.