冒險指針

在多線程環境中 ， 冒險指針是一種解決由無鎖 數據結構中的節點動態內存管理引起的問題的方法 。 這些問題通常僅在沒有自動垃圾收集的環境中出現 。 使用比較和交換原語的任何無鎖數據結構都必須處理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年被放棄 。 冒險指針的替代方法包括引用計數 。