Атомарные операции для двойного связанного списка без блокировки
Я пишу двухсвязный список без блокировки, основанный на следующих документах:
«Эффективное и надежное восстановление памяти без блокировки на основе подсчета ссылок» Андерс Гиденстам, член IEEE, Марина Папатриантафилу, Хоакан Санделл и Филиппас Цигас
«Запросы без блокировок и двусвязные списки» Håkan Sundell, Philippas Tsigas
На этот вопрос мы можем отложить первую статью.
В этой статье они используют умный способ хранения флага удаления и указателя в слове. (Больше информацииВот)
Псевдокод для этого раздела в статье:
union Link
: word
(p,d): {pointer to Node, boolean}
structure Node
value: pointer to word
prev: union Link
next: union Link
И мой код для псевдокода выше:
template< typename NodeT >
struct LockFreeLink
{
public:
typedef NodeT NodeType;
private:
protected:
std::atomic< NodeT* > mPointer;
public:
bcLockFreeLink()
{
std::atomic_init(&mPointer, nullptr);
}
~bcLockFreeLink() {}
inline NodeType* getNode() const throw()
{
return std::atomic_load(&mPointer, std::memory_order_relaxed);
}
inline std::atomic< NodeT* >* getAtomicNode() const throw()
{
return &mPointer;
}
};
struct Node : public LockFreeNode
{
struct Link : protected LockFreeLink< Node >
{
static const int dMask = 1;
static const int ptrMask = ~dMask;
Link() { } throw()
Link(const Node* pPointer, bcBOOL pDel = bcFALSE) throw()
{
std::atomic_init(&mPointer, (reinterpret_cast<int>(pPointer) | (int)pDel));
}
Node* pointer() const throw()
{
return reinterpret_cast<Node*>(
std::atomic_load(&data, std::memory_order_relaxed) & ptrMask);
}
bool del() const throw()
{
return std::atomic_load(&data, std::memory_order_relaxed) & dMask;
}
bool compareAndSwap(const Link& pExpected, const Link& pNew) throw()
{
Node* lExpected = std::atomic_load(&pExpected.mPointer, std::memory_order_relaxed);
Node* lNew = std::atomic_load(&pNew.mPointer, std::memory_order_relaxed);
return std::atomic_compare_exchange_strong_explicit(
&mPointer,
&lExpected,
lNew,
std::memory_order_relaxed,
std::memory_order_relaxed);
}
bool operator==(const Link& pOther) throw()
{
return std::atomic_load(data, std::memory_order_relaxed) ==
std::atomic_load(pOther.data, std::memory_order_relaxed);
}
bool operator!=(const Link& pOther) throw()
{
return !operator==(pOther);
}
};
Link mPrev;
Link mNext;
Type mData;
Node() {};
Node(const Type& pValue) : mData(pValue) {};
};
В этой статье есть эта функция для установки метки удаления ссылки на true:
procedure SetMark(link: pointer to pointer to Node)
while true do
node = *link;
if node.d = true or CAS(link, node, (node.p, true)) then break;
И мой код для этой функции:
void _setMark(Link* pLink)
{
while (bcTRUE)
{
Link lOld = *pLink;
if(pLink->del() || pLink->compareAndSwap(lOld, Link(pLink->pointer(), bcTRUE)))
break;
}
}
Но моя проблема вcompareAndSwap
функция, где я должен сравнить и поменять местами три атомные переменные. Информация о проблемеВот
(Фактическиnew
переменная в функции сравнения и обмена не важна, потому что она локальна для потока)
Теперь мой вопрос: как я могу написать функцию compareAndSwap для сравнения и замены трех атомных переменных или где я делаю ошибку?
(Извините за длинный вопрос)
Редактировать:
Аналогичная проблема в работе менеджера памяти:
function CompareAndSwapRef(link:pointer to pointer toNode,
old:pointer toNode, new:pointer toNode):boolean
if CAS(link,old,new) then
if new=NULL then
FAA(&new.mmref,1);
new.mmtrace:=false;
if old=NULLthen FAA(&old.mmref,-1);
return true;
return false;
и здесь я должен сравнить и обменять три атомные переменные. (Обратите внимание, что мои аргументы являются типомLink
и я должен сравнить и поменять местамиmPointer
изLink
)