Long time no seen!
After fixing tiny and absolutly not sexy issues in bullet code, programming went to an even less fancy topic: efficient temporary storage of udp packets.
Indeed, OSC messages (basically udp messages) arrives asynchronously. The display thread is running at ~60fps, but messages can pop in at any time. To avoid a display thread interruption each time a message is received, they have to be stored until the main thread request them.
The first approach was to push them in a std::vector. If the main thread never requested them, this vector might eventually become VERY long. To solve that, setting a maximum size seemed to be a good option. Each time a new message is received, if the vector is longer than maximum, the first element, witch is also the oldest, is deleted.
There’s 2 important performance issues in this approach (fixed by the new one :)):
- removing the first item ( =>resizing the vector) and push back an item at each reception ( =>resizing the vector once again) is not efficient at all;
- read and write access to the same object, implying that you can not write while reading and reverse.
Sooner in my life, someone told me about ring buffer. The name was nice and the idea behind was appealing!
Here is what has been implemented in the class that receives and parses the OSC messages (readable text below the image, click to enlarge).
polymorph::POscReceiver – ring buffer logic
POscReceiver uses ring buffer to store received messages temporarily.
If its capacity is 10, it uses an array of 10 PMessageData.
When the maximum number of messages is reached, the oldest message is overwritten.
The position of the oldest one is shifted by one each time a new message is stored in an “overflowed” array.
polymorph::POscReceiver – read and write buffer
POscReceiver uses 2 ring buffers.
Reception and parsing are managed in a separated thread.
Buffers are swapped when the main process request a read access.