O(1) não ajuda por si só. Em uma estrutura de dados sem bloqueio, é necessário haver uma única instância atômica quando sua estrutura de dados parece mudar. Todos os invariantes de representação precisam estar em vigor imediatamente antes e imediatamente após aquele instante atômico.
Isso significa que, se você estiver fazendo uma modificação na estrutura de dados, a característica importante é que você pode fazer todos os mods em uma estrutura de dados privada e depois trocar as modificações em uma única instrução atômica.
A liberdade de bloqueio geralmente é mais fácil quando suas estruturas de dados são imutáveis ( puramente funcionais ). Você simplesmente mantém um ponteiro global para a versão atual da estrutura de dados. Os leitores não precisam bloquear nada. As modificações na estrutura de dados são efetuadas trocando o ponteiro global para uma estrutura de dados imutável por outra.
Por exemplo: se você tem uma árvore equilibrada puramente funcional, você:
- Registre o ponteiro global atual na raiz da árvore.
- Crie uma nova árvore que insira ou exclua um nó. (Isso é logarítmico no tempo e no espaço no número de nós atualmente na árvore e envolve a criação de novos nós desde o ponto de modificação até a raiz e apenas apontando tudo de novo nas partes antigas da versão anterior da estrutura de dados. )
- Compare e troque atomicamente o ponteiro global para a raiz. (Observe que isso pode falhar se outra modificação ocorrer entre o momento em que você gravou o ponteiro raiz antigo e agora. Se isso acontecer, volte para a etapa 1 e tente novamente. Isso é chamado de "controle de concorrência otimista".)
Observe que a parte mais importante é o que eu disse acima sobre a necessidade de manter invariantes de representação. Geralmente, não é suficiente ter um algoritmo que faça uma alteração atomicamente no meio da árvore. Por quê? Por exemplo: você pode ter um encadeamento de leitor que está no processo de fazer uma travessia de pré-encomenda da árvore. Se você modificar um nó que é um ancestral do nó que eles estão lendo no momento, você invalidará as condições prévias que eles pensavam que haviam imposto. O leitor precisa poder trabalhar com a estrutura de dados exatamente como era antes de você fazer sua alteração, ou exatamente como será depois que você fizer sua alteração. Não é algo no meio.
Edit : Como o @Raphael apontou, existem técnicas para tornar as estruturas de dados mutáveis livres de bloqueio. Uma prova por construção de que isso sempre pode ser feito é: Contanto que você tenha um único ponteiro global para o "topo" da sua estrutura de dados, mesmo que seja mutável, você sempre poderá copiar toda a estrutura de dados, fazer seus mods para o copiar e, em seguida, usando o controle de concorrência otimista, tente comparar e trocar o ponteiro para sua estrutura de dados recém-criada para o original. A beleza das estruturas funcionais de dados baseadas em árvore é que elas mantêm o custo da cópia baixo em de uma estrutura de dados tamanho .O ( N )O(log(N))O(N)