Pular para o conteúdo

Compartilhado, contagem e referência fraca

Quando há mais de um dono legítimo — e o ciclo que a contagem não resolve.

Um dono só nem sempre é possível: um cache, um pool e um barramento de eventos têm vários interessados no mesmo objeto, e nenhum deles sabe quem é o último a sair. A contagem responde isso — e ela é determinística, diferente do coletor.

dataforge
adopt Arcane.Posse as Posse

soltos := []
c := Posse.compartilhado({"conexao": 1}, lambda v => soltos.append("fechou"))
assert c.contar() is 1

// Cada 'clonar' é mais um dono.
b := c.clonar()
d := c.clonar()
assert c.contar() is 3

// E o recurso só fecha quando o ÚLTIMO sai.
c.soltar()
b.soltar()
assert soltos is []
d.soltar()
assert soltos is ["fechou"]

"Determinística" é a palavra que importa: o fechamento acontece na linha do último `soltar`, e não quando o coletor decidir passar. Para um arquivo, isso é a diferença entre um descritor liberado agora e um liberado daqui a um minuto.

A referência fraca não conta#

dataforge
adopt Arcane.Posse as Posse

c := Posse.compartilhado({"x": 1})
f := Posse.fraco(c)

// A fraca NÃO segura o recurso vivo.
assert c.contar() is 1
assert f.vivo() is yes

// 'promover' devolve um dono de verdade — ou void, se já foi.
forte := f.promover()
assert forte is not void
assert c.contar() is 2
forte.soltar()

c.soltar()
assert f.vivo() is no
assert f.promover() is void

Para que serve a fraca#

CasoPor que fraca
um cache de objetoso cache não pode ser a razão de nada continuar vivo
o filho que aponta para o paiforte nos dois sentidos é um ciclo, e o ciclo nunca zera
um observadorquem observa não deveria impedir o observado de sumir
um índice por idele é uma conveniência, não um dono

O ciclo, que é o que a contagem não resolve#

dataforge
adopt Arcane.Posse as Posse

// Pai e filho apontando um para o outro com FORTE: a contagem de
// nenhum dos dois chega a zero, e o recurso nunca fecha.
pai := Posse.compartilhado({"nome": "pai"})
filho := Posse.compartilhado({"nome": "filho"})

// A saída: um dos lados é fraco. Aqui, o filho→pai.
fraca_para_o_pai := Posse.fraco(pai)
assert pai.contar() is 1              // a fraca não somou

pai.soltar()
assert fraca_para_o_pai.vivo() is no  // e o pai pôde sair
filho.soltar()
out "sem ciclo: o lado de volta é fraco"