C语言链表无锁化CAS,c – 无锁双链表的原子操作

我正在根据这些论文编写一个无锁双链表:

“基于引用计数的高效可靠的无锁内存回收”

Anders Gidenstam,IEEE会员,Marina Papatriantafilou,H?akan Sundell和Philippas Tsigas

“无锁的deques和双链表”

HåkanSundell,Philippas Tsigas

对于这个问题,我们可以放下第一篇论文.

在本文中,他们使用智能方法在一个单词中存储删除标志和指针.

(更多信息here)

本文中本节的伪代码:

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(pPointer) | (int)pDel));

}

Node* pointer() const throw()

{

return reinterpret_cast(

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函数中,我必须比较和交换三个原子变量.有关问题的信息是here

(实际上比较和交换函数中的新变量并不重要,因为它是线程局部的)

现在我的问题是:如何编写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)

解决方法:

除非您可以将您正在比较/交换的三个数据项放入两个指针大小的元素中,否则不能通过比较和交换执行此操作(当然不能在x86上执行此操作,并且我没有听说过任何其他机器架构有这样的事情).

如果依赖于存储在(至少)与偶数字节地址对齐的地址上的数据,则可能在删除元素时使用按位OR来设置最低位.在过去,人们一直在使用地址的上半部分来存储额外的数据,但至少在x86-64中,这是不可能的,因为地址的上半部分必须是“规范的”,这意味着任何地址位在“可用限制”(由处理器体系结构定义,当前为48位)之上,必须与可用限制的最高位相同(因此,与位47相同).

编辑:这段代码正是我所描述的:

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(pPointer) | (int)pDel));

}

Node* pointer() const throw()

{

return reinterpret_cast(

std::atomic_load(&data, std::memory_order_relaxed) & ptrMask);

}

它使用最低位来存储pDel标志.

您应该能够使用cmpxchg16b(在x86上)的形式为双链表执行此操作.在Windows系统中,这将是_InterlockedCompareExchange128.在gcc(对于Unix类型OS,例如Linux / MacOS)中,您需要首先从两个指针构造一个int128.如果您正在编译32位代码,则可能需要为Windows和Unix OS制作64位int.

标签:lock-free,c,c11,multithreading,atomic

来源: https://codeday.me/bug/20190929/1830194.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值