3 votes

Problème de AutoresetEvent et Singleton

Quelqu'un peut-il me dire ce qui ne va pas avec le code suivant ? Idéalement, il devrait d'abord démarrer un thread et ensuite attendre l'événement set. Au lieu de cela, il ne démarre pas le fil et reste bloqué sur WaitOne().

Je suis curieux de savoir ce qui est arrivé à ce fil et pourquoi ?

class Program
{   
    static void Main(string[] args)
    {
        Testing t = Testing.Instance;
        Console.Read();
    }
}

class Testing
{
    private static AutoResetEvent evt = new AutoResetEvent(false);
    public static Testing Instance = new Testing();

    private Testing()
    {
        Create();
        evt.WaitOne();
        Console.WriteLine("out");
    }

    private void Create()
    {
        Console.WriteLine("Starting thread");
        new Thread(Print).Start();
    }

    private void Print()
    {
        Console.WriteLine("started");
        evt.Set();
    }
}

EDIT : Jusqu'à présent, la description fournie par @BrokenGlass a du sens. Mais en changeant le code par le code suivant, un autre thread peut accéder aux méthodes d'instance sans que le constructeur soit terminé (suggéré par @NicoSchertler).

private static Testing _Instance;

public static Testing Instance
{
get
{
    if (_Instance == null)
        _Instance = new Testing();
    return _Instance;
}
}

5voto

BrokenGlass Points 91618

Je soupçonne que la cause première de ce comportement est que le thread créé ne peut pas accéder à la base de données de l'utilisateur. Print jusqu'à ce que le constructeur ait fini de s'exécuter - mais le constructeur ne finit jamais de s'exécuter parce qu'il attend le signal qui n'est déclenché que par la méthode Print méthode.

Remplacer le evt.WaitOne() avec un long Thread.Sleep() confirme le même comportement - le constructeur doit terminer son exécution avant qu'une méthode d'instance de l'objet puisse être exécutée depuis un autre thread.

3voto

Nico Schertler Points 10585

Le problème est que le deuxième fil est créé trop tôt. Je ne sais pas trop pourquoi, mais lorsqu'il est lancé avant le démarrage du programme principal, il ne s'exécute pas.

Vous devez utiliser le modèle singleton dans sa version originale. Cela fonctionnera.

private static Testing _Instance;

public static Testing Instance
{
    get
    {
        if (_Instance == null)
            _Instance = new Testing();
        return _Instance;
    }
}

De plus, vous ne devez pas rendre la variable evt statique. Dans la plupart des cas, la variable d'instance doit être le seul membre statique d'une classe singleton.

0voto

Chris Shain Points 33569

Je pense qu'il s'agit d'un problème de synchronisation de l'initialisation du champ statique. Essayez d'initialiser evt dans le constructeur de Testing à la place :

private static AutoResetEvent evt;
public static Testing Instance = new Testing();

private Testing()
{
    evt = new AutoResetEvent(false);
    Create();
    evt.WaitOne();
    Console.WriteLine("out");
}

Je dois noter que ce n'est qu'une supposition - j'aurais pensé que ce code fonctionnerait bien.

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