5 votes

Passage de messages du destructeur pendant la collecte des déchets

Ce qui suit me donne une violation d'accès sur Windows 32-bit, dmd.2.052, pas de drapeaux. Lorsque le destructeur est exécuté par le ramasseur d'ordures, la boîte de message semble être corrompue dans le processus.

import std.stdio;
import core.thread;
import core.memory;
import std.concurrency;

class C
{
    string m_str;
    Tid m_receiverTid;
    this(string s, Tid rt) { this.m_str = s; this.m_receiverTid = rt; }
    ~this() {   writeln("Destructor : ",this.m_str);
                m_receiverTid.send(this.m_str);
            }
}

void receiver() {
        try {
            while(true) {
                receive((string s){writeln("Received: ",s);});
            }
        } catch (Throwable th) {
            writeln("Caught throwable: ",th.toString());
        }
}

void main() {
    Tid receiverTid = spawn(&receiver);

    receiverTid.send("Basic test");
    Thread.sleep( 5_000_000 );

    C c1 = new C("c1 Manually deleted",receiverTid);
    delete c1;
    Thread.sleep( 5_000_000 );

    {
        C c2 = new C("c2 Garbage collected",receiverTid);
    }
    writeln("Running garbage collector..."); // This line needed to flush out the c2 root pointer.
    GC.collect();
    Thread.sleep( 5_000_000 );

    writeln("Exiting main thread...");
}

Ce qui précède produit :

Reçu : Test de base
Destructeur : c1 Suppression manuelle
Reçu : c1 Supprimé manuellement
Exécution du garbage collector...
Destructeur : c2 Garbage collected
Reçu : c2 Garbage collected
Attrapé throwable : object.Error : Violation d'accès
Sortie du fil principal...

Existe-t-il des solutions de contournement pour cela ?
Existe-t-il un moyen pour le code du destructeur de savoir s'il est invoqué par le GC ou non ?
Le passage de messages à partir d'un destructeur est-il intrinsèquement dangereux, par exemple si des threads non GC sont gelés par le GC alors qu'ils ont un verrou mutex sur une boîte de messages partagée, alors le GC pourrait se bloquer s'il envoie à une boîte de messages verrouillée ? Ou bien le code du destructeur n'intervient-il que dans un cycle de balayage après que tous les threads ont été dégelés ?
Est-il possible qu'un destructeur fasse référence au stockage local d'un thread, par exemple, le cycle de balayage du GC pourrait-il se dérouler dans un autre thread ?

5voto

dsimcha Points 32831

Je vois deux problèmes ici qui peuvent être liés. Le premier, référencer des sous-objets à partir d'un destructeur appelé par le GC n'est pas autorisé.

En outre, l'ordre dans lequel les ramasseur d'ordures appelle les destructeurs pour les objets non référencés n'est pas spécifié. Cela signifie que lorsque le ramasseur d'ordures appelle un destructeur pour un objet d'une classe qui a membres qui sont des références à des objets objets collectés, ces références peuvent ne plus être valides. Cela signifie que les destructeurs ne peuvent pas référencer les sous objets.

Deuxièmement, comme vous le mentionnez, les appels au destructeur n'ont lieu que dans le cycle de balayage après la reprise de tous les threads. Ils peuvent être appelés depuis un thread différent de celui qui possédait l'objet lorsqu'il était vivant. Des propositions ont été faites pour corriger ce problème, mais aucune n'a été mise en œuvre jusqu'à présent.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X