Limites para coleções sem bloqueio?

10

David Rodríguez - dribeas escreveu em um comentário no StackOverflow que "Nem todas as coleções podem ser implementadas sem bloqueios". Não tenho certeza se isso é verdade e não consigo encontrar provas de qualquer maneira.

Essa declaração não é muito precisa, mas deixe-me reformulá-la de uma maneira um pouco mais formal: para cada tipo de coleção C, existe um tipo de coleção sem bloqueio CLF que oferece o mesmo conjunto de operações e onde cada operação no CLF tem a mesma complexidade big-O que a operação correspondente ativada C.

A propósito, não espero uma transformação.

MSalters
fonte
11
Como não especialista, gostaria de saber se "sem bloqueio" pode ser rigorosamente definido.
Tsuyoshi Ito 27/01
11
@ Suresh: Talvez um sinônimo de "estrutura de dados"?
Tsuyoshi Ito 27/01
2
E se você fizer uma implementação sem bloqueio do STM (memória transacional de software) e implementar estruturas de dados além disso?
Jukka Suomela 27/01
5
@ Tsuyoshi: Eu acho que não há uma definição formal de livre de bloqueio. Informalmente, isso significa que você não usa a instrução LOCK da CPU, que é lenta e se apega à comparação e troca mais rápidas. Como um LOCK pode ser simulado com comparação e troca, é difícil estabelecer um limite rígido entre "você basicamente usa a comparação e troca aqui para simular um bloqueio (ou uma transação)" e "oh, isso é um uso realmente inteligente de comparar e trocar, e não parece como se simulasse alguma operação de nível superior que conhecemos. "
precisa saber é o seguinte
11
Tanto quanto eu entendo, sem bloqueio é aqui entendido como sinônimo de não-bloqueio. Isto não envolve a LOCKinstrução da CPU, mas o agendador de threads, através de mutexes / semáforos / etc.
precisa saber é o seguinte

Respostas:

11

Como eu estava um pouco confuso, começo esclarecendo alguns conceitos na questão.

Coleção . Não vejo razão para gastar tempo definindo rigorosamente o que "coleção" significa quando podemos simplesmente perguntar o que acontece com estruturas de dados em geral. Uma estrutura de dados ocupa uma parte da memória e possui algumas operações que podem acessar essa memória e que podem ser invocadas pelos usuários . Esses usuários podem ser processadores distintos ou apenas threads diferentes, isso não nos interessa. Tudo o que importa é que eles possam executar operações em paralelo.

Sem bloqueio . Herlihy e Boss dizem que uma estrutura de dados fica livre de bloqueios quando um usuário com falha não impede novos usos da estrutura de dados. Por exemplo, imagine que você derrame água em um processador que está no meio da inserção de um nó em um conjunto classificado. Bem, se outros processadores tentarem inserir posteriormente nesse conjunto classificado, eles terão êxito. ( Editar: De acordo com esta definição, é o caso de que, se uma estrutura de dados usa bloqueios então é não bloquear-livre, mas é não o caso de que, se uma estrutura de dados não usa fechaduras, em seguida, que é isento de bloqueio.)

Com essas definições, acho que Herlihy e Boss basicamente dizem que a resposta é transformar regiões críticas em transações.

Mas, você pode perguntar, isso tem a mesma complexidade? Não sei se a pergunta faz sentido. Considere push(x) { lock(); stack[size++] = x; unlock(); }. Esta é uma operação de tempo constante? Se você ignorar a operação de bloqueio e, portanto, outros usuários, poderá responder SIM. Se você não deseja ignorar outros usuários, realmente não há como dizer se o push será executado em tempo constante. Se você subir um nível e ver como a pilha é usada por algum algoritmo específico, poderá dizer que o push sempre levará tempo constante (medido agora em termos do que quer que seja a entrada do seu algoritmo paralelo). Mas isso realmente é uma propriedade do seu algoritmo, portanto, não faz sentido dizer que o push é uma operação de tempo constante.

Em resumo, se você ignorar o quanto um usuário executando uma operação aguarda outros usuários, o uso de transações em vez de regiões críticas responde afirmativamente à sua pergunta. Se você não ignorar o tempo de espera, precisará ver como a estrutura de dados é usada.

Radu GRIGore
fonte
Não tenho muita certeza se você pode realmente considerar que a pushoperação como declarada acima não é uma operação de tempo constante. Para um número fixo de processadores e uma implementação comum lockque não garanta fome, a operação acima (no pior caso, para um determinado processador, leva N_proc * O (1), que pode ser ingenuamente assumido como O (1) ( número de processadores a ser tidos em conta a constante oculto).
David Rodríguez - dribeas
nf(n)f
Bem, o acesso à memória é um caso comum disso. A maioria das análises de algoritmos pressupõe que o acesso à memória seja O (1) independente da memória usada; arquiteturas de memória real (com caches etc) são melhor aproximadas por O (log N) onde N é a memória usada.
MSalters 31/01
Embora a suposição de que o número de processadores seja uma constante seja bastante prática, evitarei isso. A questão é que a complexidade não pode ser analisada de maneira unidimensional, pois o tamanho do problema provavelmente aumentará tanto no tamanho da entrada quanto no número de processadores, os quais são dimensões ortogonais. Supondo que um contêiner específico na biblioteca padrão C ++ (obviamente estou escolhendo um difícil), um dos requisitos é que todos os elementos sejam mantidos em um bloco contíguo de memória.
David Rodríguez - dribeas
Agora, anexar um elemento ao vetor é uma operação de tempo constante amortizada (se não couber no bloco alocado anteriormente, a chamada levará um tempo linear no número de elementos no contêiner, mas se o bloco de memória reservado for adquirido após uma sequência exponencial, o custo amortizado é constante). Se você implementar um contêiner seguro de encadeamento, trava e executa a alteração, o custo da operação é proporcional ao custo do bloqueio - o que eu realmente não sei ... mas em uma primeira aproximação, você pode considerar principalmente constante
David Rodríguez - dribeas
3

Eu acho que "COLEÇÕES" significa "filas, pilhas, listas vinculadas, árvores, ..."

De http://www.cl.cam.ac.uk/research/srg/netos/lock-free/

Através de um design e implementação cuidadosos, é possível construir estruturas de dados seguras para uso simultâneo sem a necessidade de gerenciar bloqueios ou encadeamentos de blocos. Essas estruturas de dados sem bloqueio podem aumentar o desempenho, permitindo simultaneidade extra e podem melhorar a robustez, evitando alguns dos problemas causados ​​pela inversão de prioridade nas configurações locais ou por falhas de máquinas e links em sistemas distribuídos.

A melhor introdução geral aos nossos algoritmos sem bloqueio é o artigo Programação simultânea sem bloqueios, atualmente em fase de submissão, que abrange nossos projetos de memória transacional de software baseada em palavras e de comparação e troca de várias palavras, e memória transacional de software baseada em objetos.

Se "sem bloqueio" significa "não use semáforos, mutex, monitores, ..." do sistema operacional, então acho (mas não sou especialista) que toda coleção pode ser feita sem bloqueio usando leitura atômica de gravação / gravação modificar primitivas que devem ser suportadas pelo hardware.

O()

Documentação exaustiva sobre o assunto pode ser encontrada online:

http://www.google.it/search?q=lock+free+algorithm+filetype%3Apdf

(... e mais referências no final de cada documento)

Marzio De Biasi
fonte