Итак, существует интеловский код по реализации потокобезопасной очереди "один пишет - один читает".
Там, как вы заметили, есть конструкции примерно такого типа:
const_cast <const volatile node*> (param) //это в load_consume
const_cast <volatile node*> (param) // это в store_release.
Вопрос состоит в том, для чего нужны эти ключевые слова в const_cast и чем они отличаются (а видимо, они отличаются) от стандартной конструкции по типу const_cast <node*> (param)?
А это не относится конкретно к вопросу, тут мои попытки пояснить код. Возможно, это поможет понять кому-то (но пока что не мне), зачем там вообще const_cast?
Если интересно насчёт того, что есть там конкретно по этим двум методам, то, насколько я понял, то все узлы (node), а именно head, tail, next, tail_copy и first обозначены как указатели на некие объекты, построенные в соответствии со структурой node (в нём лежит ссылка на следующий узел и значение). То есть, это всё объявляется как node* и выглядит в остальных местах как &node.
load_consume по своей логике принимает указатель и возвращает значение по ней, но по факту это значение из-за выше указанных вещей - тоже указатель. Указатель на этот указатель мы и передаём в качестве параметра в этот метод. Также он делает const_cast, о котором я спрашивал, и вызывает барьер памяти, который говорит процессорам, чтобы завершали все свои незавершённые операции.
Один раз load_consume используется, чтобы проверить, не пуста ли очередь: он пытается взять этот указатель на tail->next, если "не смог" (видимо, в самом конце лежит нулевое значение), то считается, что больше ничего в очереди нет.
В другом месте (alloc_node) он просто передаёт одному указателю другой указатель.
store_release принимает указатель и значение, затем разыменовывает первое и даёт значение второго. Как говорил, всё это является указателями, то есть, разыменованному указателю на указатель даётся "значение" на другой указатель. Также там тоже есть барьер памяти.
И уж совсем не по теме, но по их коду, отвечать совсем не обязательно: зачем там нужны cache_line_size и cache_line_pad, а также конструкция ниже?
spsc_queue(spsc_queue const&);
spsc_queue& operator = (spsc_queue const&);
const_cast <const volatile type*>: или так можно указать, какой именно именно спецификатор удалить, или, наоборот, придаёт чему-то этот спецификатор (не удаляет).И, судя по логике кода, тут как раз второе. В
load_consumeникакое внешнее содержимое (параметр) не меняется, а значит, этот параметр можно сделать константой. Ну и в обоих случаях мы, собственно, добавляем ещёvolatile.Мне осталось выяснить, каков ответ на последний вопрос.
– brenoritvrezorkre Apr 23 '16 at 06:10