I have a high-priority process that needs to pass data to a low-priority process. I've written a basic ring buffer to handle the passing of data:
class RingBuffer {
public:
RingBuffer(int size);
~RingBuffer();
int count() {return (size + end - start) % size;}
void write(char *data, int bytes) {
// some work that uses only buffer and end
end = (end + bytes) % size;
}
void read(char *data, int bytes) {
// some work that uses only buffer and start
start = (start + bytes) % size;
}
private:
char *buffer;
const int size;
int start, end;
};
Here's the problem. Suppose the low-priority process has an oracle that tells it exactly how much data needs to be read, so that count()
need never be called. Then (unless I'm missing something) there are no concurrency issues. However, as soon as the low-priority thread needs to call count()
(the high-priority thread might want to call it too to check if the buffer is too full) there is the possibility that the math in count() or the update to end is not atomic, introducing a bug.
I could put a mutex around the accesses to start and end but that would cause priority inversion if the high-priority thread has to wait for the lock acquired by the low-priority thread.
I might be able to work something out using atomic operations but I'm not aware of a nice, cross-platform library providing these.
Is there a standard ring-buffer design that avoids these issues?