我一直在研究无锁堆栈。
我正在阅读这个link和弹出功能让我想知道。
根据该链接,弹出功能实现如下。
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;
}
在上面的实现中,我们通过使用单独的标签信息来解决阿坝问题。
到目前为止,一切顺利。
但我的问题是。next.head = orig.head->next;
行是线程安全的吗?
如果next.head = orig.head->next;
行在线程1中的free(orig.head);
之后在线程2中恢复,这不是一个错误,因为我们在orig.head
被释放之后引用next
?
我看到的链接没有提到这个问题,所以我想知道这是否安全。
1条答案
按热度按时间jtjikinw1#
next.head = orig.head->next;
行是线程安全的吗?如果
next.head = orig.head->next;
行在线程1中的free(orig.head);
之后在线程2中恢复,这不是一个错误,因为我们在orig.head
被释放之后引用next?你已经在函数中发现了一个真正的缺陷。干得好
两个线程并发执行
lfstack_pop()
确实可以将相同的值加载到各自的orig
局部变量中。尽管每个线程的orig
都是该线程的本地指针,但两个orig.head
指针都指向同一个对象。在这种情况下,如果一个线程在另一个线程执行orig.head-〉next之前执行
free()操作它的
orig.head,那么第二个线程将由于取消引用不确定的指针值而获得未定义的行为。没有什么特别的东西阻止它。 请注意,就C语言规范而言,即使在过渡期间,在
orig.head`最初指向的地址处分配了新节点,该行为仍然是未定义的。(这就是阿坝问题出现的情况,代码声称要解决这个问题。