Храните адрес и bool в одном слове для двойного связанного списка без блокировки
Я читаю какую-то статью для двойного связанного списка без блокировки. В этих документах они хранят адрес следующего и предыдущего узла и флаг в одном слове (int).
Это потому, что в 32-разрядных архитектурах все адреса выровнены по 4-байтовым границам, поэтому все адреса кратны 4?
и если причина в том, что я говорю, этот код в порядке?
const int dMask = 1;
const int pMask = ~dMask;
int store(void* pPointer, bool pDel)
{
return reinterpret_cast<int>(pPointer) | (int)pDel;
}
void load(int pData, void** pPointer, bool* pDel)
{
*pPointer = reinterpret_cast<void*>(pData & pMask);
*pDel = pData & dMask;
}
И еще вопрос: у других платформ, таких как мобильные устройства Android, выше идея правильна?
2 ответа
Вы более или менее правы. Это обычная оптимизация пространства в коде очень низкого уровня. Это не портативный. (Вы можете сделать его немного более портативным, используя intptr_t
вместо int
.)
Кроме того, конечно, выравнивание справедливо только для указателей на более сложные типы; char*
не обязательно будет выровнен. (Я видел только один раз, когда это использовалось, при реализации управления памятью, когда все задействованные блоки должны быть достаточно выровнены для любого типа.)
Наконец, я не уверен, что авторы статьи пытаются сделать, но код, который вы публикуете, не может быть использован в многопоточной среде, по крайней мере, на современных машинах. Чтобы гарантировать, что модификация в одном потоке видна в другом потоке, вам нужно использовать атомарные типы, или какой-то вид ограждения или мембраны.
Адреса в большинстве 32-битных архитектур хранятся не в 4-байтовых границах, а в 1-байтовых. Они читаются из памяти с шагом 4 байта (типичный размер слова). Не видя код для этого двусвязного списка, похоже, что они применяют некоторые правила для того, как контейнер будет хранить данные.