-
Notifications
You must be signed in to change notification settings - Fork 39
atomic queue not always atomic #33
Comments
Yes, single producer, single consumer. That is a very good bug report. |
The easiest fix would be to just hit it with a big hammer and make all the loads and stores of head and tail volatile. This is probably not going to you you anything in a typical situation because the work registers are going to be flushed any way. There is a potential for needlessly restricting the optimizer though in the case that the user pops multiple values next to each other. We are currently working on a range library which would potentially solve this inefficiency by providing a range based pop:
which would pop until either the output range is full or the queue is empty and returns the modified output range. This would allow us to do the most efficient thing possible in all cases. It also makes super slick looking syntax like:
|
Before working on the queue here are a few questions of taste / suggestions. Feel free to shoot them down for any reason ;)
if we call foo with a full queue we may be surprised that during
turns into more code than
especially if n is a power of 2. I would expect the optimizer to make the same code if |
I can recommend everyone to read the following papers by Hans Boehm who was involved with the new memory model for C++11:
We might have to rethink all our concurrency primitives in light of these new C++11 capabilities. Does anyone (@salkinium, @dergraaf or @odinthenerd) know how well the C++11 memory model is implemented for the |
https://github.com/roboterclubaachen/xpcc/blob/develop/src/xpcc/architecture/driver/atomic/queue_impl.hpp#L132
I assume the queue is single producer and single consumer (doesn't say so in the docs but judging by the implementation). Even so there are potential problems in the improbable case that a user is pushing to the queue at lower priority and popping at high priority and sets the high priority interrupt manually it is not guaranteed that the high priority will actually see all the bytes in the queue.
Here some psydo code:
//queue is empty here
MyUartTxQueue::push(3); //this gets inlined
setInterrupt(UartTx); //this gets reordered by the optimizer into the middle of the body of push
//uart ISR is called but new value of head has not yet been flushed to ram so last byte will not be sent untill the next time something is sent over the uart.
Sorry for being pedantic, you guys do seem to have put a lot more effort into concurrency than many prominent libs out there.
The text was updated successfully, but these errors were encountered: