So, there is Intel's code for implementing a thread-safe queue "one writes one reads."
There, as you noticed, there are constructions of approximately the following type:
const_cast <const volatile node*> (param) //это в load_consume const_cast <volatile node*> (param) // это в store_release. The question is, why are these keywords in const_cast needed and how do they differ (and apparently they differ) from the standard construction of the type const_cast <node*> (param) ?
And this does not apply specifically to the question, here are my attempts to explain the code. Perhaps this will help someone understand (but not yet me), why is there a const_cast at const_cast ?
If you are interested in what is there specifically in these two methods, then, as far as I understand, all nodes (namely), namely head , tail , next , tail_copy and first designated as pointers to certain objects constructed in accordance with the structure node (it contains a link to the next node and value). That is, this is all declared as node* and looks like &node elsewhere.
load_consume to its logic, load_consume takes a pointer and returns a value according to it, but in fact this value is also a pointer because of the above things. We also pass a pointer to this pointer as a parameter to this method. It also makes a const_cast , about which I asked, and causes a memory barrier that tells the processors to complete all of its incomplete operations.
Once load_consume used to check if the queue is not empty: it tries to take this pointer to tail->next , if it “could not” (apparently, at the very end is zero), then it is considered that there is nothing more in the queue.
Elsewhere ( alloc_node ) it simply passes another pointer to one pointer.
store_release takes a pointer and a value, then dereferences the first and gives the value of the second. As he said, all this is a pointer, that is, a pointer to a pointer to a pointer is given a "value" to another pointer. Also there is a memory barrier.
And it’s completely off topic, but according to their code, it’s not at all necessary to answer: why do we need cache_line_size and cache_line_pad , as well as the construction below?
spsc_queue(spsc_queue const&); spsc_queue& operator = (spsc_queue const&);
const_cast <const volatile type*>: either so you can specify which particular qualifier to remove, or, on the contrary, this qualifier attaches to something (does not remove). And, judging by the logic of the code, here is just the second. Inload_consumeno external content (parameter) changes, which means that this parameter can be made constant. Well and in both cases we, actually, add stillvolatile. It remains for me to find out what the answer to the last question is. - brenoritvrezorkre