Skip to content
Open
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ddf8ea0
Fix: Safeguard `try` for `std::thread`
ashvardanian Oct 9, 2025
0ec9ae9
Docs: Why no Miri or Loom?
ashvardanian Oct 9, 2025
916e641
Add: Draft Zig binding
ashvardanian Oct 10, 2025
d9455c8
Improve: Thread name formatting
ashvardanian Oct 10, 2025
fb063a7
Fix: Use aligned allocs for `opaque_pool_t`
ashvardanian Oct 11, 2025
0b9ed05
Improve: Handle `void` contexts
ashvardanian Oct 11, 2025
6d6283a
Make: Upgrade Zig to v0.16
ashvardanian Oct 11, 2025
bf998f9
Add: Bench against libXEV and Spice
ashvardanian Oct 11, 2025
ca3d42b
Improve: Static slicing for `std.Thread.Pool`
ashvardanian Oct 11, 2025
e8c6b48
Improve: Test C stable API
ashvardanian Oct 11, 2025
a21ac35
Make: Skip C11 tests on MSVC - lacking atomics
ashvardanian Oct 11, 2025
1e9540f
Make: Apple's `libSystem` contains Blocks runtime
ashvardanian Oct 11, 2025
18b6d63
Improve: Add `worker_yield_t` hook for idle backoff
guillaumeriousat Oct 8, 2025
101a955
Fix: Route `standard_worker_yield` through `micro_yield()`
guillaumeriousat Oct 8, 2025
53e1b5d
Improve: Select worker-yield overloads with `if constexpr`
guillaumeriousat Oct 9, 2025
541842c
Improve: Shared `call_yield_` with & w/out thread
ashvardanian Oct 11, 2025
ac41200
Merge branch 'pr/feat-worker-yield' into main-dev
ashvardanian Oct 11, 2025
86b95aa
Merge branch 'zig' into main-dev
ashvardanian Oct 11, 2025
bbb9e90
Add: NUMA-aware allocator for Zig
ashvardanian Oct 11, 2025
0167211
Make: Backport to Zig 0.15
ashvardanian Oct 11, 2025
a707d55
Fix: Deprecate `spice` comparison
ashvardanian Oct 11, 2025
9982ad9
Improve: `RoundRobinVec` code nesting
ashvardanian Oct 18, 2025
46bb382
Improve: Validate `CacheAligned` padding
ashvardanian Oct 18, 2025
3bf34e9
Fix: Over-aligned `AllocationResult`
ashvardanian Oct 19, 2025
e7932c4
Add: Reductions in Rust
ashvardanian Oct 19, 2025
cb6b257
Add: Stoppable & Exception-handling `try_for`
ashvardanian Oct 19, 2025
0911619
Break: Name spacing/capitalization
ashvardanian Oct 19, 2025
9a08a62
Make: Bump CI
ashvardanian Oct 22, 2025
7de0186
Merge: WFET patches
ashvardanian Mar 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Improve: Select worker-yield overloads with if constexpr
Drops the extra template parameter by using `code if constexpr` so worker threads hand their index to `code worker_yield_t` only when that overload exists.
  • Loading branch information
guillaumeriousat authored and ashvardanian committed Oct 11, 2025
commit 53e1b5d43de65230b263d4f3083e39ff118fac54
40 changes: 15 additions & 25 deletions include/fork_union.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,18 +299,6 @@ struct standard_yield_t {
inline void operator()() const noexcept { std::this_thread::yield(); }
};

/**
* @brief Yield function called by worker threads in between tasks.
*
* This implementation does not use the thread index but a user could use
* this to implement more complex yield behaviours.
*/
template <typename micro_yield_type, typename thread_index_t_ = std::size_t>
struct standard_worker_yield_t {
micro_yield_type micro_yield;
inline void operator()(FU_MAYBE_UNUSED_ thread_index_t_ idx) const noexcept { micro_yield; }
};

/**
* @brief A synchronization point that waits for all threads to finish the last fork.
* @note You don't have to explicitly call any of the APIs, it's like `std::jthread` ;)
Expand Down Expand Up @@ -1015,16 +1003,16 @@ constexpr bool can_be_for_slice_callback() noexcept {
* ------------------------------------------------------------------------------------------------
*
* @tparam allocator_type_ The type of the allocator to be used for the thread pool.
* @tparam micro_yield_type_ The type of the yield function to be used for busy-waiting.
* @tparam micro_yield_type_ The type of the yield function to be used for busy-waiting. If an overload of
* operator()(index_type_ thread_index) exists, worker threads will call it with their thread index.
* @tparam index_type_ Use `std::size_t`, but or a smaller type for debugging.
* @tparam alignment_ The alignment of the thread pool. Defaults to `default_alignment_k`.
*/
template < //
typename allocator_type_ = std::allocator<std::thread>, //
typename micro_yield_type_ = standard_yield_t, //
typename index_type_ = std::size_t, //
std::size_t alignment_ = default_alignment_k, //
typename worker_yield_type = standard_worker_yield_t<micro_yield_type_, index_type_> //
template < //
typename allocator_type_ = std::allocator<std::thread>, //
typename micro_yield_type_ = standard_yield_t, //
typename index_type_ = std::size_t, //
std::size_t alignment_ = default_alignment_k //
>
class basic_pool {

Expand All @@ -1038,9 +1026,6 @@ class basic_pool {

using index_t = index_type_;
static_assert(std::is_unsigned<index_t>::value, "Index type must be an unsigned integer");
using worker_yield_t = worker_yield_type;
static_assert(std::is_nothrow_invocable_r<void, worker_yield_t, index_t>::value,
"Worker yield must be callable with a index_t argument & return void");
using epoch_index_t = index_t; // ? A.k.a. number of previous API calls in [0, UINT_MAX)
using thread_index_t = index_t; // ? A.k.a. "core index" or "thread ID" in [0, threads_count)
using colocation_index_t = index_t; // ? A.k.a. "NUMA node ID" in [0, numa_nodes_count)
Expand Down Expand Up @@ -1416,10 +1401,15 @@ class basic_pool {
// Wait for either: a new ticket or a stop flag
epoch_index_t new_epoch; // Will definitely be initialized in the loop
mood_t mood = mood_t::grind_k; // May not be initialized in the loop
worker_yield_t worker_yield;
micro_yield_t micro_yield;
while ((new_epoch = epoch_.load(std::memory_order_acquire)) == last_epoch &&
(mood = mood_.load(std::memory_order_acquire)) == mood_t::grind_k)
worker_yield(thread_index);
(mood = mood_.load(std::memory_order_acquire)) == mood_t::grind_k) {
// Call micro_yield with the current thread's index if possible.
if constexpr (std::is_nothrow_invocable_r<void, micro_yield_t, index_t>::value)
micro_yield(thread_index);
else
micro_yield();
}

if (fu_unlikely_(mood == mood_t::die_k)) break;
if (fu_unlikely_(mood == mood_t::chill_k) && (new_epoch == last_epoch)) {
Expand Down