History
There is a stream of letters periodically collecting data from somewhere (in real time, but this does not really matter in the question). After that, many read this data. The usual solution for this is with two reader latches and two such buffers:
Writer (case 1): acquire lock 0 loop write to current buffer acquire other lock free this lock swap buffers wait for next period
or
Writer (case 2): acquire lock 0 loop acquire other lock free this lock swap buffers write to current buffer wait for next period
Problem
In both methods, if another lock operation fails, the replacement is not performed, and the author overwrites his previous data (because the writer is in real time, he cannot wait for readers). Thus, in this case, all readers lose this data frame.
This is not such a big problem, but readers are my own code, and they are short, so this problem is solved with a double buffer, and if a problem occurs, I could make it a triple buffer (or more).
The problem is the delay, which I want to minimize. Imagine case 1:
writer writes to buffer0 reader is reading buffer1 writer can't acquire lock1 because reader is still reading buffer1 | | | reader finishes reading, | (writer waiting for next period) <- **this point** | | writer wakes up, and again writes to buffer0
At ** this point **, other theoretical readers could read buffer0
data, if only the writer could swap after the reader has finished, rather than waiting for his next period. What happened in this case is that only one reader was a little late, all readers missed one frame of data, while the problem could be completely avoided.
Case 2 is similar:
writer writes to buffer0 reader is idle | | | reader finishes reading, | (writer waiting for next period) | | reader starts reading buffer1 writer wakes up | it can't acquire lock0 because reader is still reading buffer1 overwrites buffer0
I tried mixing solutions, so the writer tries to exchange buffers immediately after recording, and if this is not possible, immediately after waking up in the next period. So something like this:
Writer (case 3): acquire lock 0 loop if last buffer swap failed acquire other lock free this lock swap buffers write to current buffer acquire other lock free this lock swap buffers wait for next period
Now the delay problem persists:
writer writes to buffer0 reader is reading buffer1 writer can't acquire lock1 because reader is still reading buffer1 | | | reader finishes reading, | (writer waiting for next period) <- **this point** | | writer wakes up swaps buffers writes to buffer1
Again at ** this point ** all readers can start reading buffer0
, which is a short delay after buffer0
been written, but instead they should wait for the next write period.
Question
The question is, how can I handle this? If I want the script to be executed exactly in the right period, it needs to wait for the period using the RTAI function, and I cannot do it like
Writer (case 4): acquire lock 0 loop write to current buffer loop a few times or until the buffer has been swapped sleep a little acquire other lock free this lock swap buffers wait for next period
This leads to jitter. because "several times" may turn out to be longer than "waiting for the next period", so the writer may skip the beginning of his period.
To be more clear, here is what I want:
writer writes to buffer0 reader is reading buffer1 | | | reader finishes reading, | (writer waiting for next period) As soon as all readers finish reading, | the buffer is swapped | readers start reading buffer0 writer wakes up | writes to buffer1
What i found already
I found read-copy-update , which, as I understand it, continues to allocate memory for buffers and frees them until readers do with them, which is impossible for me for many reasons. First, threads are shared between the kernel and user space. Secondly, with RTAI you cannot allocate memory in a real-time stream (because then your stream will cause Linux system calls and, therefore, disrupt real performance! (Not to mention that using your own RCU implementation in Linux is useless from for the same reasons)
I also thought that there is an extra thread that tries to swap buffers at a higher frequency, but that doesn't seem like such a good idea. Firstly, he himself would have to synchronize with the writer, and secondly, itβs good that I have many of these reader writers working in different parts in parallel, and one additional stream for each writer just seems too big. One thread for all authors seems very complicated in terms of synchronization with each author.