Theme Catppuccin
Make yourself at homeCatppuccin

A softer light for long learning sessions.

Appearance

Loading your preference…

Dark palette

Choose a dark palette to try it.

Light uses Latte. Your choices stay in this browser.

Back to your source shelf

Inside the companion

Renderer Engineering

Explore bounded image work, allocator lifetimes, cancellation, and Asio coroutines.

Project files 15

Bound a batch of work

Jobs, options, results, and the blocking batch interface.

77 lines worker_pool.hpp
#pragma once
#include <condition_variable>
#include <cstddef>
#include <cstdint>
#include <expected>
#include <memory>
#include <mutex>
#include <optional>
#include <stop_token>
#include <vector>

namespace prism_engineering {
inline constexpr std::size_t max_jobs = 32;
inline constexpr std::size_t max_samples_per_job = 4096;
inline constexpr std::size_t max_workers = 8;

// A deterministic admission gate, useful for testing cancellation before work.
// shared_ptr ownership in Options keeps the gate alive until every worker
// joins.
class WorkGate {
public:
  bool arrive_and_wait(std::stop_token stop);
  bool wait_for_arrivals(std::size_t count, std::stop_token stop = {});
  void open();

private:
  std::mutex mutex_;
  std::condition_variable_any changed_;
  std::size_t arrivals_{};
  bool open_{};
};

struct Job {
  std::uint64_t generation{};
  std::vector<std::uint32_t> samples; // Queued payload owns its storage.
  bool inject_failure{}; // Explicit experiment seam, not an external callback.
};
enum class Status { pending, succeeded, cancelled, failed };
struct Result {
  std::uint64_t generation{};
  Status status{Status::pending};
  std::uint64_t checksum{};
};
struct Options {
  std::size_t workers{2};
  std::shared_ptr<WorkGate> gate;
  // Test seam: simulate failure before launching worker N (zero-based).
  // The default launches normally; values >= workers do not trigger it.
  std::optional<std::size_t> fail_launch_after{};
};
struct Report {
  std::vector<Result>
      results; // One fixed slot per accepted job, no growing result queue.
  std::size_t peak_active{};
};
enum class Error {
  invalid_worker_count,
  too_many_jobs,
  payload_too_large,
  allocation,
  thread_start,
  worker_runtime
};

// The caller transfers a bounded batch into this function. Workers execute
// asynchronously, but this orchestration call returns ONLY after joining them.
// Cancellation is cooperative; it does not interrupt arbitrary blocking I/O.
[[nodiscard]] std::expected<Report, Error>
run_batch(std::vector<Job> owned_jobs, Options options = {},
          std::stop_token cancellation = {});
// A generation check is a policy on values, not a claim that cancellation
// undoes work. The caller applies it before publishing a result to the current
// asset.
[[nodiscard]] bool accepts(const Result &result,
                           std::uint64_t current_generation) noexcept;
} // namespace prism_engineering

This is the file included with the course. Copy and download give you its complete source.

Taking your work offline? Download all course companions