一直在研究无锁栈
我正在阅读这个link,弹出功能让我感到疑惑。
根据链接,pop函数实现如下
int lfstack_pop(_Atomic lfstack_t *lfstack)
{
lfstack_t next, orig = atomic_load(lfstack);
do{
if(orig.head == NULL)
{
return -1;
}
next.head = orig.head->next;
next.tag = orig.tag+1; //increase the "tag"
}while(!atomic_compare_exchange_weak(lfstack,&orig,next));
printf("poping value %d\n",orig.head->data);
free(orig.head);
return 0;
}
在上面的实现中,我们通过使用单独的标签信息来解决ABA问题。
到目前为止,一切都很好。
但我的问题是这个。
next.head = orig.head->next;
行是线程安全的吗?
如果线
next.head = orig.head->next;
在线程 1 中的 free(orig.head);
之后在线程 2 中恢复,那不是一个错误,因为我们在 next
被释放后引用 orig.head
吗?
我正在看的链接没有提到这个问题,所以我想知道这是否安全。
线
线程安全吗?next.head = orig.head->next;
如果线
在线程2之后恢复next.head = orig.head->next;
在线程 1 中,这不是一个错误,因为我们是 在free(orig.head);
被释放后引用下一个?orig.head
你已经确定了函数中的善意缺陷。干得好。
确实有可能同时执行
lfstack_pop()
的两个线程将相同的值加载到各自的orig
局部变量中。尽管每个线程的 orig
是该线程的本地指针,但两个 orig.head
指针都指向同一个对象。在这种情况下,如果一个线程在另一个线程评估 `orig.head->next 之前继续执行 free()
ing orig.head
,那么第二个线程将由于取消引用不确定的指针值而获得未定义的行为。没有什么特别可以阻止的。
请注意,就 C 语言规范而言,即使在此期间,在
orig.head
最初指向的地址分配了一个新节点,该行为仍未定义。 (这是代码声称要解决的 ABA 问题出现的情况。)