How to correctly implement triple buffering?

早过忘川 提交于 2019-12-08 02:21:47

问题


I am trying to simulate videocard (producer thread) and a monitor(consumer thread), to figure out what is going on in educational purposes. So here is the technical task description:

Producer thread produces frames pixel data at 1000 fps. Consumer thread runs at 60 fps and every frame it must have access to last produced frame for at least 1/60th of second. Each frame is represented by some int*, for simplicity.

So my solution is that i have array of 2 pointers: one for producer, one for consumer. And plus some free, unused pointer, which is not owned by consumer or producer at any given moment of time.

#define Producer 0
#define Consumer 1
int* usedPointers[2];
std::atomic<int*> freePointer;
  • producer always writes frame pixels to usedPointers[Producer], then does usedPointers[Producer] = freePointer.exchange(usedPointers[Producer], memorySemanticsProducer); so that last completely produced frame is now pointed by freePointer, and its free to write new frame, not destroying last actual complete frame.

  • consumer does usedPointers[Consumer] = freePointer.exchange(usedPointers[Consumer], memorySemanticsConsumer); so that it would own last actual frame data, and then is free to access usedPointers[Consumer] as long, as it desires to.

Correct me if i am wrong.

I miss what is memorySemanticsXXX. There are descriptions but i cannot figure out which exactly should i use in every thread and why. So i am asking for some hints on that.


回答1:


memorySemanticsXXX you're mentioning are about the rest of your code surrounding the exchange() lines. The default behavior for std::atomic::exchange() is that memory_order_seq_cst is used (the second parameter for exchange() you're not using).

This means three things at the same time:

  • Any code you wrote before your exchange() call is guaranteed to execute before that call (otherwise compiler optimizations can reorder your code) and the results of that execution will be visible in all other threads (CPU cache propagation) before the exchange() call is made.
  • The same as previous but for the code you wrote after your exchange() line.

  • All of the code before and after exchange() call is executed in the exact order you wrote it (including other atomic operations).

So, the whole point is that you may choose not to have one, two or all three of these restrictions, which can bring you speed improvements. You shouldn't bother with this unless you have a performance bottleneck. If there's no bottleneck then just use std::atomic without the second parameter (it will take the default value).

In case you don't use all three restrictions you have to be really careful writing your code otherwise it can unpredictably crash.

Read more about it here: Memory order



来源:https://stackoverflow.com/questions/49352853/how-to-correctly-implement-triple-buffering

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!