Trie结构,无锁插入

问题描述

我尝试实现无锁 Trie 结构,但我卡在插入节点上。起初我认为这很容易(我的特里结构没有任何删除方法),但即使以原子方式交换一个指针也很棘手。 我想仅当它是 nullptr 时才以原子方式交换指针以指向结构(TrieNode),以确保我不会丢失其他线程可以插入的其他点头。

struct TrieNode{
    int t =0;
    std::shared_ptr<TrieNode> child{nullptr};
};
   std::shared_ptr<TrieNode> root;
   auto p = std::atomic_load(&root);
   auto node =  std::make_shared<TrieNode>();
   node->t=1;


   auto tmp = std::shared_ptr<TrieNode>{nullptr};
   std::cout<<std::atomic_compare_exchange_strong( &(p->child),&tmp,node)<<std::endl;
   std::cout<<node->t;

使用此代码,我得到退出代码 -1073741819 (0xC0000005)。

编辑:感谢您的所有评论。也许我没有具体说明我的问题,所以我现在想解决它。经过大约 10 个小时的编码,最后一天我改变了一些东西。现在我使用普通指针,现在它正在工作。我现在没有测试它是否可以通过多个线程插入单词来自由竞争。我打算今天做。

const int ALPHABET_SIZE =4;
enum  Alphabet {A,T,G,C,END};
class LFTrie{
private:
    struct TrieNode{
        std::atomic<TrieNode*> children[ALPHABET_SIZE+1];
    };
    std::atomic<TrieNode*> root = new TrieNode();
public:
void Insert(std::string word){
        auto p =root.load();
        int index;
        for(int i=0; i<=word.size();i++){

            if(i==word.size())
                index = END;
            else
                index = WhatIndex(word[i]);
            auto expected = p->children[index].load();
            if(!expected){
                auto node = new TrieNode();
                if(! p->children[index].compare_exchange_strong(expected,node))
                    delete node;
            }
            p = p->children[index];
        }
    }
};

现在我相信它可以与插入不同单词的许多线程一起使用。是的,在这解决方案中,如果下一个指针不为空,我会丢弃节点。很抱歉给您带来麻烦(我不是母语人士)。

解决方法

CAS 模式应该类似于:

auto expected = p->child;
while( !expected ){
  if (success at CAS(&p->child,&expected,make_null_replace() ))
    break;
}

如果您不注意返回值/预期并测试您正在替换本地存储的 null,那么您就有麻烦了。

失败时,您需要丢弃您创建的新节点。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...