I've been studying the lock free stack.
I was reading this link and the pop function got me wondering.

根据链接,弹出功能实现如下.

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;
}

In the above implementation, we are solving the ABA problem by using separate tag information.
So far, so good.

But my question is this.
Is the line next.head = orig.head->next; thread-safe?

如果行next.head = orig.head->next;在线程1中的free(orig.head);之后在线程2中继续,这不是一个错误吗,因为我们在orig.head被释放之后引用next

我正在查看的链接没有提到这个问题,所以我想知道这是否安全.

推荐答案

next.head = orig.head->next;线是线程安全的吗?

如果线next.head = orig.head->next;在线程2之后恢复 free(orig.head);在线程1中,这不是一个错误吗,因为我们 是否在orig.head已释放后引用下一个?

您已经在该函数中发现了一个bona fide缺陷.做得好.

对于同时执行lfstack_pop()的两个线程来说,将相同的值加载到它们各自的orig个局部变量中确实是可能的.尽管每个线程的orig都是该线程的本地线程,但两个orig.head指针指向相同的对象.在这种情况下,如果一个线程在另一个线程对其orig.head求值之前执行free(),则第二个线程将由于取消引用不确定的指针值而获得未定义的行为.没有什么特别的事情可以阻止这一点.

请注意,就C语言规范而言,行为仍然是未定义的,即使在过渡期间,在orig.head最初指向的地址上分配了新 node .(这就是代码声称要解决的ABA问题出现的情况.)

C++相关问答推荐

使用sd-设备列举设备导致seg错误

初始化char数组-用于初始化数组的字符串是否除了存储数组的位置之外单独存储在内存中

为什么这个select()会阻止?

为什么getchar()挂起了,尽管poll()返回了一个好的值?""

在C中使用强制转换将uint16_t转换为uint8_t [2]是否有效?

不同到达时间的轮询实现

为什么复合文字(C99)的返回会生成更多的汇编代码?

当我运行/调试C程序时,Malloc()似乎正在将&q;r\r...&q;赋值给一个指针,我不确定为什么?

在C++中头文件中声明外部 struct

Ruby C Api处理异常

轮询libusb_pollfd struct 列表的正确方式是什么?

如何在下面的C代码中正确管理内存?

如何使用_newindex数组我总是得到错误的参数

Boyer Moore算法的简单版本中的未定义行为

Tcl_GetDoubleFromObj在列表的迭代中是一个缺点

C: NULL>;NULL总是false?

这些表达式是否涉及 C 中定义的复合文字?

C Makefile - 如何避免重复提及文件名

是什么阻止编译器优化手写的 memcmp()?

快速准确计算double的小数指数