Sto scrivendo una classe che è approssimativamente analoga a un CancellationToken , tranne che ha un terzo stato per "non essere mai cancellato". Al momento sto cercando di decidere cosa fare se la 'fonte' del token è raccolta di dati inutili senza essere mai impostata.
Sembra che, in modo intuitivo, l'origine debba trasferire il token associato allo stato "mai annullato" quando sta per essere raccolto. Tuttavia, questo potrebbe attivare richiami che sono stati mantenuti in vita solo dal loro collegamento dal token. Ciò significa cosa potrebbero ora fare riferimento a questi callback nel processo di finalizzazione. Chiamarli sarebbe male.
Per "risolvere" questo problema, ho scritto questa classe:
public sealed class GCRoot {
private static readonly GCRoot MainRoot = new GCRoot();
private GCRoot _next;
private GCRoot _prev;
private object _value;
private GCRoot() {
this._next = this._prev = this;
}
private GCRoot(GCRoot prev, object value) {
this._value = value;
this._prev = prev;
this._next = prev._next;
_prev._next = this;
_next._prev = this;
}
public static GCRoot Root(object value) {
return new GCRoot(MainRoot, value);
}
public void Unroot() {
lock (MainRoot) {
_next._prev = _prev;
_prev._next = _next;
this._next = this._prev = this;
}
}
}
intendendo usarlo in questo modo:
Source() {
...
_root = GCRoot.Root(callbacks);
}
void TransitionToNeverCancelled() {
_root.Unlink();
...
}
~Source() {
TransitionToNeverCancelled();
}
ma ora sono turbato. Questo sembra aprire la possibilità di perdite di memoria, senza in realtà risolvere tutti i casi di fonti nel limbo. Ad esempio, se una sorgente viene chiusa in uno dei suoi callback, viene rootata dalla radice di callback e quindi non può mai essere raccolta.
Presumibilmente dovrei lasciare che le mie fonti vengano raccolte senza sbirciare. O forse no? È mai opportuno provare a controllare l'ordine di finalizzazione o è un gigantesco segnale di pericolo?