Question

j'ai un cours (voir exemple ci-dessous) qui agit comme un wrapper .NET pour une structure de mémoire CUDA,
alloué à l'aide de cudaMalloc() et référencé à l'aide d'un champ membre de type IntPtr.
(La classe utilise DllImport d'une DLL C native qui englobe diverses fonctionnalités CUDA.)

Les méthodes dispose vérifient si le pointeur est IntPtr.Zero et sinon appelle cudaFree()
qui libère avec succès la mémoire (renvoie le succès de CUDA)
et définit le pointeur sur IntPtr.Zero.

La méthode finalize appelle la méthode dispose.

Le problème c'est-à-dire que si les méthodes finalize sont appelées sans que la disposition soit appelée auparavant,
alors la fonction cudaFree() définit un code d'erreur de "pointeur de périphérique invalide".

J'ai vérifié et l'adresse reçue par cudaFree() est la même adresse renvoyée par cudaMalloc() et aucun dispose() n'a été appelé précédemment.

Lorsque j'ajoute un appel explicite à dispose(), la même adresse est libérée avec succès.

La seule solution de contournement que j'ai trouvée était de ne pas appeler la méthode dispose à partir du finaliseur. Cependant, cela pourrait provoquer une fuite de mémoire si dispose() n'est pas toujours appelé.

Avez-vous une idée de pourquoi cela se produit ?- J'ai rencontré le même problème avec CUDA 2.2 et 2.3, sous .NET 3.5 SP1 sous Windows Vista 64bits + GeForce 8800 et sous Windows XP 32bits + Quadro FX (je ne sais pas quel numéro).

class CudaEntity : IDisposable
{
    private IntPtr dataPointer;

    public CudaEntity()
    {
        // Calls cudaMalloc() via DllImport,
        // receives error code and throws expection if not 0
        // assigns value to this.dataPointer
    }

    public Dispose()
    {
        if (this.dataPointer != IntPtr.Zero)
        {
            // Calls cudaFree() via DllImport,
            // receives error code and throws expection if not 0

            this.dataPointer = IntPtr.Zero;
        }
    }

    ~CudaEntity()
    {
        Dispose();
    }
}
{
    // this code works
    var myEntity = new CudaEntity();
    myEntity.Dispose();
}
{
    // This code cause a "invalid device pointer"
    // error on finalizer's call to cudaFree()
    var myEntity = new CudaEntity();
}
Était-ce utile?

La solution

Le problème est que les finaliseurs sont exécutés sur le thread GC, les ressources CUDA allouées dans un thread ne peuvent pas être utilisées dans un autre.Un extrait du guide de programmation CUDA :

Plusieurs threads hôtes peuvent s’exécuter code de l’appareil sur le même appareil, mais en conception, un thread hôte peut exécuter code de l’appareil sur un seul appareil.En tant que Par conséquent, plusieurs threads hôtes sont requis pour exécuter le code de l’appareil sur plusieurs appareils.De plus, tout CUDA Ressources créées par le biais de l’environnement d’exécution dans un thread hôte ne peut pas être utilisé par le runtime à partir d’un autre thread hôte.

Le mieux est d'utiliser le using déclaration, qui garantit que le Dispose() La méthode est toujours appelée à la fin du bloc de code « protégé » :

using(CudaEntity ent = new CudaEntity())
{

}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top