BluFedora Job System v1.0.0
This is a C++ job system library for use in game engines.
Job::MPMCQueue Class Reference

#include <job_queue.hpp>

Classes

struct  IndexRange
 

Public Types

using size_type = std::size_t
 
using atomic_size_type = std::atomic< size_type >
 
using value_type = unsigned char
 

Public Member Functions

 MPMCQueue ()=default
 
 ~MPMCQueue ()=default
 
void Initialize (value_type *const memory_backing, const size_type capacity) noexcept
 
bool PushExact (const value_type *elements, const size_type num_elements)
 
size_type PushUpTo (const value_type *elements, const size_type num_elements)
 
bool PopExact (value_type *out_elements, const size_type num_elements)
 
size_type PopUpTo (value_type *out_elements, const size_type num_elements)
 

Private Member Functions

template<bool allOrNothing>
size_type PushImpl (const value_type *elements, const size_type num_elements)
 
template<bool allOrNothing>
size_type PopImpl (value_type *out_elements, const size_type num_elements)
 
template<bool allOrNothing>
bool RequestWriteRange (IndexRange *out_range, const size_type num_items)
 
template<bool allOrNothing>
bool RequestPopRange (IndexRange *out_range, const size_type num_items)
 
size_type WriteElements (const value_type *const elements, const IndexRange range)
 
size_type ReadElements (value_type *const out_elements, const IndexRange range) const
 
void Commit (atomic_size_type *commit, const IndexRange range) const
 
size_type Distance (const size_type a, const size_type b) const
 

Private Attributes

atomic_size_type m_ProducerPending
 
atomic_size_type m_ProducerCommited
 
unsigned char m_Padding0 [k_FalseSharingPadSize - sizeof(atomic_size_type) *2]
 
atomic_size_type m_ConsumerPending
 
atomic_size_type m_ConsumerCommited
 
unsigned char m_Padding1 [k_FalseSharingPadSize - sizeof(atomic_size_type) *2]
 
value_typem_Queue
 
size_type m_Capacity
 
unsigned char m_Padding2 [k_FalseSharingPadSize - sizeof(m_Queue) - sizeof(m_Capacity)]
 

Detailed Description

Definition at line 378 of file job_queue.hpp.


Class Documentation

◆ Job::MPMCQueue::IndexRange

struct Job::MPMCQueue::IndexRange

Definition at line 386 of file job_queue.hpp.

Class Members
size_type start
size_type end

Member Typedef Documentation

◆ size_type

using Job::MPMCQueue::size_type = std::size_t

Definition at line 381 of file job_queue.hpp.

◆ atomic_size_type

Definition at line 382 of file job_queue.hpp.

◆ value_type

using Job::MPMCQueue::value_type = unsigned char

Definition at line 383 of file job_queue.hpp.

Constructor & Destructor Documentation

◆ MPMCQueue()

Job::MPMCQueue::MPMCQueue ( )
default

◆ ~MPMCQueue()

Job::MPMCQueue::~MPMCQueue ( )
default

Member Function Documentation

◆ Initialize()

void Job::MPMCQueue::Initialize ( value_type *const  memory_backing,
const size_type  capacity 
)
inlinenoexcept

Definition at line 408 of file job_queue.hpp.

409 {
410 m_ProducerPending.store(0, std::memory_order_relaxed);
411 m_ProducerCommited.store(0, std::memory_order_relaxed);
412 m_ConsumerPending.store(0, std::memory_order_relaxed);
413 m_ConsumerCommited.store(0, std::memory_order_relaxed);
414 m_Queue = memory_backing;
415 m_Capacity = capacity;
416 }
atomic_size_type m_ProducerPending
Definition: job_queue.hpp:393
atomic_size_type m_ProducerCommited
Definition: job_queue.hpp:394
size_type m_Capacity
Definition: job_queue.hpp:400
atomic_size_type m_ConsumerCommited
Definition: job_queue.hpp:397
atomic_size_type m_ConsumerPending
Definition: job_queue.hpp:396
value_type * m_Queue
Definition: job_queue.hpp:399

References m_Capacity, m_ConsumerCommited, m_ConsumerPending, m_ProducerCommited, m_ProducerPending, and m_Queue.

◆ PushExact()

bool Job::MPMCQueue::PushExact ( const value_type elements,
const size_type  num_elements 
)
inline

Definition at line 420 of file job_queue.hpp.

421 {
422 return PushImpl<true>(elements, num_elements) != 0u;
423 }

◆ PushUpTo()

size_type Job::MPMCQueue::PushUpTo ( const value_type elements,
const size_type  num_elements 
)
inline

Definition at line 425 of file job_queue.hpp.

426 {
427 return PushImpl<false>(elements, num_elements);
428 }

◆ PopExact()

bool Job::MPMCQueue::PopExact ( value_type out_elements,
const size_type  num_elements 
)
inline

Definition at line 430 of file job_queue.hpp.

431 {
432 return PopImpl<true>(out_elements, num_elements) != 0u;
433 }

◆ PopUpTo()

size_type Job::MPMCQueue::PopUpTo ( value_type out_elements,
const size_type  num_elements 
)
inline

Definition at line 435 of file job_queue.hpp.

436 {
437 return PopImpl<false>(out_elements, num_elements);
438 }

◆ PushImpl()

template<bool allOrNothing>
size_type Job::MPMCQueue::PushImpl ( const value_type elements,
const size_type  num_elements 
)
inlineprivate

Definition at line 442 of file job_queue.hpp.

443 {
444 IndexRange range;
445 if (RequestWriteRange<allOrNothing>(&range, num_elements))
446 {
447 const size_type written_elements = WriteElements(elements, range);
448 Commit(&m_ProducerCommited, range);
449 return written_elements;
450 }
451
452 return 0u;
453 }
void Commit(atomic_size_type *commit, const IndexRange range) const
Definition: job_queue.hpp:566
std::size_t size_type
Definition: job_queue.hpp:381
size_type WriteElements(const value_type *const elements, const IndexRange range)
Definition: job_queue.hpp:538

References Commit(), m_ProducerCommited, and WriteElements().

◆ PopImpl()

template<bool allOrNothing>
size_type Job::MPMCQueue::PopImpl ( value_type out_elements,
const size_type  num_elements 
)
inlineprivate

Definition at line 456 of file job_queue.hpp.

457 {
458 IndexRange range;
459 if (RequestPopRange<allOrNothing>(&range, num_elements))
460 {
461 const size_type read_elements = ReadElements(out_elements, range);
462 Commit(&m_ConsumerCommited, range);
463 return read_elements;
464 }
465
466 return 0u;
467 }
size_type ReadElements(value_type *const out_elements, const IndexRange range) const
Definition: job_queue.hpp:552

References Commit(), m_ConsumerCommited, and ReadElements().

◆ RequestWriteRange()

template<bool allOrNothing>
bool Job::MPMCQueue::RequestWriteRange ( IndexRange out_range,
const size_type  num_items 
)
inlineprivate

Definition at line 470 of file job_queue.hpp.

471 {
472 size_type old_head, new_head;
473
474 old_head = m_ProducerPending.load(std::memory_order_relaxed);
475 do
476 {
477 const size_type tail = m_ConsumerCommited.load(std::memory_order_acquire);
478
479 size_type capacity_left = Distance(old_head, tail);
480 if constexpr (allOrNothing)
481 {
482 if (capacity_left < num_items)
483 {
484 capacity_left = 0;
485 }
486 }
487
488 if (capacity_left == 0)
489 {
490 return false;
491 }
492
493 const size_type num_element_to_write = capacity_left < num_items ? capacity_left : num_items;
494
495 new_head = old_head + num_element_to_write;
496
497 } while (!m_ProducerPending.compare_exchange_weak(old_head, new_head, std::memory_order_relaxed, std::memory_order_relaxed));
498
499 *out_range = {old_head, new_head};
500 return true;
501 }
size_type Distance(const size_type a, const size_type b) const
Definition: job_queue.hpp:579

References Distance(), m_ConsumerCommited, and m_ProducerPending.

◆ RequestPopRange()

template<bool allOrNothing>
bool Job::MPMCQueue::RequestPopRange ( IndexRange out_range,
const size_type  num_items 
)
inlineprivate

Definition at line 504 of file job_queue.hpp.

505 {
506 size_type old_tail, new_tail;
507
508 old_tail = m_ConsumerPending.load(std::memory_order_relaxed);
509 do
510 {
511 const size_type head = m_ProducerCommited.load(std::memory_order_acquire);
512 const size_type distance = Distance(head, old_tail);
513
514 size_t capacity_left = (m_Capacity - distance);
515 if constexpr (allOrNothing)
516 {
517 if (capacity_left < num_items)
518 {
519 capacity_left = 0;
520 }
521 }
522
523 if (!capacity_left)
524 {
525 return false;
526 }
527
528 const size_type num_element_to_read = capacity_left < num_items ? capacity_left : num_items;
529
530 new_tail = old_tail + num_element_to_read;
531
532 } while (!m_ConsumerPending.compare_exchange_weak(old_tail, new_tail, std::memory_order_relaxed, std::memory_order_relaxed));
533
534 *out_range = {old_tail, new_tail};
535 return true;
536 }

References Distance(), m_Capacity, m_ConsumerPending, and m_ProducerCommited.

◆ WriteElements()

size_type Job::MPMCQueue::WriteElements ( const value_type *const  elements,
const IndexRange  range 
)
inlineprivate

Definition at line 538 of file job_queue.hpp.

539 {
540 const size_type real_start = range.start % m_Capacity;
541 const size_type write_size = Distance(real_start, range.end % m_Capacity);
542 const size_type capacity_before_split = m_Capacity - real_start;
543 const size_type num_items_before_split = write_size < capacity_before_split ? write_size : capacity_before_split;
544 const size_type num_items_after_split = write_size - num_items_before_split;
545
546 std::copy_n(elements + 0u, num_items_before_split, m_Queue + real_start);
547 std::copy_n(elements + num_items_before_split, num_items_after_split, m_Queue + 0u);
548
549 return write_size;
550 }

References Distance(), Job::MPMCQueue::IndexRange::end, m_Capacity, m_Queue, and Job::MPMCQueue::IndexRange::start.

Referenced by PushImpl().

◆ ReadElements()

size_type Job::MPMCQueue::ReadElements ( value_type *const  out_elements,
const IndexRange  range 
) const
inlineprivate

Definition at line 552 of file job_queue.hpp.

553 {
554 const size_type real_start = range.start % m_Capacity;
555 const size_type read_size = Distance(real_start, range.end % m_Capacity);
556 const size_type capacity_before_split = m_Capacity - real_start;
557 const size_type num_items_before_split = read_size < capacity_before_split ? read_size : capacity_before_split;
558 const size_type num_items_after_split = read_size - num_items_before_split;
559
560 std::copy_n(std::make_move_iterator(m_Queue + real_start), num_items_before_split, out_elements + 0u);
561 std::copy_n(std::make_move_iterator(m_Queue + 0u), num_items_after_split, out_elements + num_items_before_split);
562
563 return read_size;
564 }

References Distance(), Job::MPMCQueue::IndexRange::end, m_Capacity, m_Queue, and Job::MPMCQueue::IndexRange::start.

Referenced by PopImpl().

◆ Commit()

void Job::MPMCQueue::Commit ( atomic_size_type commit,
const IndexRange  range 
) const
inlineprivate

Definition at line 566 of file job_queue.hpp.

567 {
568 size_type start_copy;
569 while (!commit->compare_exchange_weak(
570 start_copy = range.start,
571 range.end,
572 std::memory_order_release,
573 std::memory_order_relaxed))
574 {
576 }
577 }
void PauseProcessor() noexcept
CPU pause instruction to indicate when you are in a spin wait loop.

References Job::MPMCQueue::IndexRange::end, Job::PauseProcessor(), and Job::MPMCQueue::IndexRange::start.

Referenced by PopImpl(), and PushImpl().

◆ Distance()

size_type Job::MPMCQueue::Distance ( const size_type  a,
const size_type  b 
) const
inlineprivate

Definition at line 579 of file job_queue.hpp.

580 {
581 return (b > a) ? (b - a) : m_Capacity - a + b;
582 }

References m_Capacity.

Referenced by ReadElements(), RequestPopRange(), RequestWriteRange(), and WriteElements().

Member Data Documentation

◆ m_ProducerPending

atomic_size_type Job::MPMCQueue::m_ProducerPending
private

Definition at line 393 of file job_queue.hpp.

Referenced by Initialize(), and RequestWriteRange().

◆ m_ProducerCommited

atomic_size_type Job::MPMCQueue::m_ProducerCommited
private

Definition at line 394 of file job_queue.hpp.

Referenced by Initialize(), PushImpl(), and RequestPopRange().

◆ m_Padding0

unsigned char Job::MPMCQueue::m_Padding0[k_FalseSharingPadSize - sizeof(atomic_size_type) *2]
private

Definition at line 395 of file job_queue.hpp.

◆ m_ConsumerPending

atomic_size_type Job::MPMCQueue::m_ConsumerPending
private

Definition at line 396 of file job_queue.hpp.

Referenced by Initialize(), and RequestPopRange().

◆ m_ConsumerCommited

atomic_size_type Job::MPMCQueue::m_ConsumerCommited
private

Definition at line 397 of file job_queue.hpp.

Referenced by Initialize(), PopImpl(), and RequestWriteRange().

◆ m_Padding1

unsigned char Job::MPMCQueue::m_Padding1[k_FalseSharingPadSize - sizeof(atomic_size_type) *2]
private

Definition at line 398 of file job_queue.hpp.

◆ m_Queue

value_type* Job::MPMCQueue::m_Queue
private

Definition at line 399 of file job_queue.hpp.

Referenced by Initialize(), ReadElements(), and WriteElements().

◆ m_Capacity

size_type Job::MPMCQueue::m_Capacity
private

Definition at line 400 of file job_queue.hpp.

Referenced by Distance(), Initialize(), ReadElements(), RequestPopRange(), and WriteElements().

◆ m_Padding2

unsigned char Job::MPMCQueue::m_Padding2[k_FalseSharingPadSize - sizeof(m_Queue) - sizeof(m_Capacity)]
private

Definition at line 401 of file job_queue.hpp.


The documentation for this class was generated from the following file: