patterncppMinor
Lockless, blocking, non synchronized multiple producers and consumers ring buffer
Viewed 0 times
buffernonblockingsynchronizedmultipleandproducerslocklessringconsumers
Problem
My program is structured like this: there are
There must be no intra-group synchronization, that is producers need not to synchronize work on a single
Here's what I came up with C++11. I seek for advice especially on the usage of the various relaxed memory models. I have checked the assembly and my code seems not to produce any
```
#ifndef MULTIQUEUE_HPP_
#define MULTIQUEUE_HPP_
#include
#include
#include
#include
template
class multiqueue_cacheline{
const int inthread, outthread;
const size_t ringsize, unblockproducer, unblockconsumer;
struct ref{
std::atomic v;
bool eof;
char padding[linesize > sizeof(v) + sizeof(eof) ? linesize - sizeof(v) - sizeof(eof) : 0];
ref(int v): v(v), eof(false) {}
ref(const ref& o): v(o.v.load(std::memory_order_relaxed)), eof(false) {}
};
std::vector refs;
std::atomic inring = {0};
struct sleepobj{
std::condition_variable cond;
std::mutex m;
template
void sleep(T& ready){
std::unique_lock lk(m);
if(!ready()) cond.wait(lk, ready);
}
void wake(){
std::unique_lock lk(m);
cond.notify_all();
}
} co
M producer threads, each of which computes a section of an object O with index i O[i]. When a specific O[i] is completed by all producers, it is put in a ring buffer, which is consumed by N threads. When all consumers are done with a specific O[i] can be discarded.There must be no intra-group synchronization, that is producers need not to synchronize work on a single
O[i], as well as consumers. The objects must appear in order in the ring though. Also, the speed of production and consumption can vary wildly, so a consumer that cannot acquire an element from the ring must block, and if a producer is about to start working on an element but the ring is full, it shall block. In all the other cases, insertion and removal should be lock free.Here's what I came up with C++11. I seek for advice especially on the usage of the various relaxed memory models. I have checked the assembly and my code seems not to produce any
mfence instruction on x86, only some lock when incrementing reference counting. Is that correct and expected?```
#ifndef MULTIQUEUE_HPP_
#define MULTIQUEUE_HPP_
#include
#include
#include
#include
template
class multiqueue_cacheline{
const int inthread, outthread;
const size_t ringsize, unblockproducer, unblockconsumer;
struct ref{
std::atomic v;
bool eof;
char padding[linesize > sizeof(v) + sizeof(eof) ? linesize - sizeof(v) - sizeof(eof) : 0];
ref(int v): v(v), eof(false) {}
ref(const ref& o): v(o.v.load(std::memory_order_relaxed)), eof(false) {}
};
std::vector refs;
std::atomic inring = {0};
struct sleepobj{
std::condition_variable cond;
std::mutex m;
template
void sleep(T& ready){
std::unique_lock lk(m);
if(!ready()) cond.wait(lk, ready);
}
void wake(){
std::unique_lock lk(m);
cond.notify_all();
}
} co
Solution
-
You are trying to align each
Aligning a member within a class to a cacheline seems to be a non trivial exercise. This question on SO might be helpful.
-
Your code is really hard to understand from just reading mostly due to not very helpful names for parameters to the class. It's not very obvious what the
You are trying to align each
ref object to a cache line by padding the object to fill an entire cache line. However your refs vector is embedded as a member in the multiqueue class hence it will start at an offset relative to the beginning of the object which is probably either aligned on a 4 or 8 byte boundary. So your refs vector might start in the middle of a cache line and your padding to cache line size ill not gain you what you wanted.Aligning a member within a class to a cacheline seems to be a non trivial exercise. This question on SO might be helpful.
-
Your code is really hard to understand from just reading mostly due to not very helpful names for parameters to the class. It's not very obvious what the
inthread, outthread, unblockconsumer and unblockproducer parameters mean and in how far they relate to the workings of the queue. I assume inthread is numberOfProducers and outthread is numberOfConsumers - the others are bit more convoluted. Adding some documentation comments would help.Context
StackExchange Code Review Q#65292, answer score: 3
Revisions (0)
No revisions yet.