lock-free ABA问题重现

2019-07-29  本文已影响0人  Teech

在多线程编程中,同步时会发生ABA问题。上述代码就是重现ABA问题,当一个地址需要被read2次,这个值没有改变意味着没有人修改这个值。然而其他线程执行可能会修改这个值在两次read之间,只是又把这个值修改回去了。

  1. 初始化栈 top->A->B->C
    Push(&C);
    Push(&B);
    Push(&A);
  1. thread1的worker1先运行,thread2阻塞到等待信号量。thread1中的局部变量retPtr指向A,nextPtr指向B,接着post信号量,然后sleep 2秒,有足够的时间让thread2 执行完代码
    for(;;){
        struct Obj* retPtr = topPtr;
        if(!retPtr)
            return NULL;
        struct Obj* nextPtr  = retPtr->next;
        //第一步 retPtr指向A nextPtr指向B
        if(bSleep)
        {
            sem_post(&Sema); //post信号量
            sleep(2);
            fprintf(stdout,"i am wake up topPtr.value[%c] retPtr.value[%c] nextPtr.value[%c]\n",((struct Obj*)topPtr)->value,retPtr->value,nextPtr->value);
        }
        if(topPtr.compare_exchange_weak(retPtr,nextPtr))
            return retPtr;
    }
  1. thread2的worker2开始运行了,最后结果为top->A->C.注意这里A我们是全局的变量,不会被释放的。这里就等于模拟了,释放了A后,在分配一块内存,内存地址和A是一样的。
    Pop(false); //top -> B -> C
    Pop(false); //top -> C
    Push(&A);   //top ->A -> C
  1. thread1的worker1开始苏醒过来了。执行这段代码,判断topPtr和retPtr地址都相同,所以就用nextPtr替换topPtr,注意到步骤1中,nextPtr指向B的,要知道B在步骤3中第一个Pop中已经被释放了。
        if(topPtr.compare_exchange_weak(retPtr,nextPtr))
            return retPtr;

运行的结果如下

Obj A malloc
Obj B malloc
Obj C malloc
worker1 is work
worker2 is wake
worker2 is over
i am wake up topPtr.value[A] retPtr.value[A] nextPtr.value[B]
worker1 is over
Obj C free
Obj B free
Segmentation fault

为了保证每次必定crash,我在调用之后把栈上数据清0,所以一定会崩溃。

    testFun();
    char array[64] = {0,};      //栈上之前分配的B,C虽然已经释放掉了,但是栈上数据还存在。所以把栈数据清0,让其必定崩溃。
    struct Obj* APtr = topPtr;
上一篇 下一篇

猜你喜欢

热点阅读