美文网首页
lock-free ABA问题重现

lock-free ABA问题重现

作者: Teech | 来源:发表于2019-07-29 17:19 被阅读0次

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

    • 线程P1读取值A从共享内存中
    • P1运行后,P2在运行。
    • P2 修改存储A的共享内存修改为B,然后在修改回A
    • P1继续执行,发现存储A的共享内存处的值并没有变化,于是继续运行
      这个可能会造成一些隐藏的问题在修改这块共享内存之后。
      最经常会出现ABA问题的一个情况,就是编写lock-free程序时,包含指针的情况。如果一个item从列表中移出以及释放掉,接着一个新的item被分配以及加入列表。新分配的item和之前释放掉的item指针相同这个经常会发生的(基于内存分配器的分配策略)。这个就导致了ABA问题了。
      简书中链接跳转到github一直提示不安全的链接,所以把链接贴进来。https://github.com/iamjokerjun/abaTest
      这个是个ABA问题的栈操作。列举下步骤
    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;
    

    相关文章

      网友评论

          本文标题:lock-free ABA问题重现

          本文链接:https://www.haomeiwen.com/subject/bitirctx.html