冒险指针

在多线程环境中， 冒险指针是一种解决由无锁 数据结构中的节点动态内存管理引起的问题的方法。 这些问题通常仅在没有自动垃圾收集的环境中出现。 Anthony Williams. C++ Concurrency in Action: Practical Multithreading. Manning:Shelter Island, 2012. See particularly Chapter 7.2, "Examples of lock-free data structures". 

使用比较和交换原语的任何无锁数据结构都必须处理ABA问题。 例如，在使用链表实现的无锁堆栈中，一个线程可能正在尝试从堆栈的前面弹出项目（A→B→C）。 它会记住自栈顶而下的第二个值“B”，然后执行 compare_and_swap(target=&head, newvalue=B, expected=A) 不幸的是，在此操作正在执行时，另一个线程可能执行了两次弹出操作，然后将A推回顶部，从而导致堆栈（A→C）。 比较并交换成功将“ head”与“ B”交换，结果是堆栈现在包含垃圾数据（指向已经被释放的元素“ B”的指针）。 

此外，任何包含以下形式代码的无锁算法   Node* currentNode = this->head; // assume the load from "this->head" is atomic
  Node* nextNode = currentNode->next; // assume this load is also atomic 在没有自动垃圾收集的情况下，它还面临另一个主要问题。 在这两行之间，另一个线程可能会弹出this->head指向的节点并对其进行内存分配，这意味着通过第二行上的currentNode进行的内存访问读取了已释放的内存（实际上可能已经被另外一部分程序用在了不同的地方）。 

冒险指针可用于同时解决这两个问题。 在使用冒险指针的系统中，每个线程都保留一个冒险指针的列表 ，这些指针指示该线程当前正在访问的节点。 （在许多系统中，此“列表”可能只限于一个 或两个元素。 ）冒险指针列表上的节点不得被任何其他线程修改或释放。  当线程希望删除一个节点时，它将其放置在“稍后释放”的节点列表上，但实际上直到其他线程的危险列表中没有包含指针时才真正释放该节点的内存。 可以通过专用的垃圾回收线程来完成此手动垃圾回收（如果所有线程共享“稍后释放”的列表）；或者，可以由每个工作线程自行清除“待释放”列表，作为诸如“ pop”之类的操作的一部分（在这种情况下，每个工作线程可以负责其自己的“待释放”列表）。 

在2002年， IBM的 Maged Michael提出了关于冒险指针技术的美国专利申请， 但该申请在2010年被放弃。 

冒险指针的替代方法包括引用计数 。 Anthony Williams. C++ Concurrency in Action: Practical Multithreading. Manning:Shelter Island, 2012. See particularly Chapter 7.2, "Examples of lock-free data structures". 

 参见 

 并发数据结构
 冒险(计算机体系结构)

 参考文献 



 外部链接 

 并发构建块  -冒险指针（称为“ SMR”）和其他无锁数据结构的C ++实现。 还有Java接口。 
 并发工具包  -冒险指针和无锁数据结构的C实现 
 Atomic Ptr Plus  - 具有冒险指针实现的C / C ++库 
 并行转换和C++的内存模型  -附录中包含Windows的下的C++实现 
 libcds  - 无锁容器和冒险指针实现的C++库 

Category:程序架構