2011-04-23 14 views
5

El siguiente me da una Infracción de acceso en Windows de 32 bits, dmd.2.052, sin flags. Cuando el destructor es ejecutado por el recolector de basura, el cuadro de mensaje parece estar dañado en el proceso.Mensaje que pasa desde destructor durante la recolección de basura

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..."); 
} 

Lo anterior produce:

Received: Basic test
Destructor : c1 Manually deleted
Received: c1 Manually deleted
Running garbage collector...
Destructor : c2 Garbage collected
Received: c2 Garbage collected
Caught throwable: object.Error: Access Violation
Exiting main thread...

¿Hay soluciones para este?
¿Hay alguna manera de que el código del destructor sepa si está siendo invocado por el GC o no?
El mensaje que pasa desde un destructor es intrínsecamente inseguro, p. si los subprocesos no GC están congelados por el GC mientras tienen un bloqueo mutex en un cuadro de mensaje compartido, entonces ¿el GC podría estancarse si se envía a un cuadro de mensaje bloqueado? ¿O el código destructor solo tiene lugar en un ciclo de barrido después de que se hayan descongelado todos los hilos?
¿Es seguro que un destructor haga referencia al almacenamiento local de subprocesos, p. podría el ciclo de barrido GC estar en un hilo diferente?

Respuesta

5

Veo dos problemas aquí que pueden estar relacionados. En primer lugar, referencing subobjects from a destructor called by the GC is not allowed.

Furthermore, the order in which the garbage collector calls destructors for unreference objects is not specified. This means that when the garbage collector calls a destructor for an object of a class that has members that are references to garbage collected objects, those references may no longer be valid. This means that destructors cannot reference sub objects.

En segundo lugar, como usted menciona, llamadas destructor no sólo tienen lugar en el ciclo de barrido después de todas las discusiones se reanudaron. Pueden ser llamados desde un hilo diferente al que poseía el objeto cuando estaba vivo. Hay propuestas sobre la mesa para solucionar esto, pero hasta ahora no se han implementado.

Cuestiones relacionadas