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 376 of file job_queue.hpp.


Class Documentation

◆ Job::MPMCQueue::IndexRange

struct Job::MPMCQueue::IndexRange

Definition at line 384 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 379 of file job_queue.hpp.

◆ atomic_size_type

Definition at line 380 of file job_queue.hpp.

◆ value_type

using Job::MPMCQueue::value_type = unsigned char

Definition at line 381 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 405 of file job_queue.hpp.

406 {
407 m_ProducerPending.store(0, std::memory_order_relaxed);
408 m_ProducerCommited.store(0, std::memory_order_relaxed);
409 m_ConsumerPending.store(0, std::memory_order_relaxed);
410 m_ConsumerCommited.store(0, std::memory_order_relaxed);
411 m_Queue = memory_backing;
412 m_Capacity = capacity;
413 }
atomic_size_type m_ProducerPending
Definition: job_queue.hpp:391
atomic_size_type m_ProducerCommited
Definition: job_queue.hpp:392
size_type m_Capacity
Definition: job_queue.hpp:398
atomic_size_type m_ConsumerCommited
Definition: job_queue.hpp:395
atomic_size_type m_ConsumerPending
Definition: job_queue.hpp:394
value_type * m_Queue
Definition: job_queue.hpp:397

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 417 of file job_queue.hpp.

418 {
419 return PushImpl<true>(elements, num_elements) != 0u;
420 }

◆ PushUpTo()

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

Definition at line 422 of file job_queue.hpp.

423 {
424 return PushImpl<false>(elements, num_elements);
425 }

◆ PopExact()

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

Definition at line 427 of file job_queue.hpp.

428 {
429 return PopImpl<true>(out_elements, num_elements) != 0u;
430 }

◆ PopUpTo()

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

Definition at line 432 of file job_queue.hpp.

433 {
434 return PopImpl<false>(out_elements, num_elements);
435 }

◆ PushImpl()

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

Definition at line 439 of file job_queue.hpp.

440 {
441 IndexRange range;
442 if (RequestWriteRange<allOrNothing>(&range, num_elements))
443 {
444 const size_type written_elements = WriteElements(elements, range);
445 Commit(&m_ProducerCommited, range);
446 return written_elements;
447 }
448
449 return 0u;
450 }
void Commit(atomic_size_type *commit, const IndexRange range) const
Definition: job_queue.hpp:563
std::size_t size_type
Definition: job_queue.hpp:379
size_type WriteElements(const value_type *const elements, const IndexRange range)
Definition: job_queue.hpp:535

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 453 of file job_queue.hpp.

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

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 467 of file job_queue.hpp.

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

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 501 of file job_queue.hpp.

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

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 535 of file job_queue.hpp.

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

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 549 of file job_queue.hpp.

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

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 563 of file job_queue.hpp.

564 {
565 size_type start_copy;
566 while (!commit->compare_exchange_weak(
567 start_copy = range.start,
568 range.end,
569 std::memory_order_release,
570 std::memory_order_relaxed))
571 {
573 }
574 }
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 576 of file job_queue.hpp.

577 {
578 return (b > a) ? (b - a) : m_Capacity - a + b;
579 }

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 391 of file job_queue.hpp.

Referenced by Initialize(), and RequestWriteRange().

◆ m_ProducerCommited

atomic_size_type Job::MPMCQueue::m_ProducerCommited
private

Definition at line 392 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 393 of file job_queue.hpp.

◆ m_ConsumerPending

atomic_size_type Job::MPMCQueue::m_ConsumerPending
private

Definition at line 394 of file job_queue.hpp.

Referenced by Initialize(), and RequestPopRange().

◆ m_ConsumerCommited

atomic_size_type Job::MPMCQueue::m_ConsumerCommited
private

Definition at line 395 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 396 of file job_queue.hpp.

◆ m_Queue

value_type* Job::MPMCQueue::m_Queue
private

Definition at line 397 of file job_queue.hpp.

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

◆ m_Capacity

size_type Job::MPMCQueue::m_Capacity
private

Definition at line 398 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 399 of file job_queue.hpp.


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