Question Quelle est la différence entre ManualResetEvent et AutoResetEvent dans .NET?


J'ai lu la documentation à ce sujet et je pense comprendre. Un AutoResetEvent se réinitialise lorsque le code passe par event.WaitOne(), mais un ManualResetEvent ne fait pas.

Est-ce correct?


472
2017-09-30 16:33


origine


Réponses:


Oui. C'est comme la différence entre un péage et une porte. le ManualResetEvent est la porte, qui doit être fermée (réinitialisée) manuellement. le AutoResetEvent est un poste de péage, permettant à une voiture de passer et de se fermer automatiquement avant que la prochaine puisse passer.


823
2017-09-30 17:03



Imaginez que le AutoResetEvent exécute WaitOne() et Reset() comme une seule opération atomique.


110
2017-09-30 18:55



La reponse courte est oui. La différence la plus importante est qu'un AutoResetEvent n'autorise qu'un seul thread en attente à continuer. D'autre part, un ManualResetEvent continuera à autoriser les threads, plusieurs à la même heure, à continuer jusqu'à ce que vous lui disiez d'arrêter (le réinitialiser).


46
2017-09-30 16:59



Tiré du livre C # 3.0 Nutshell, par   Joseph Albahari

Filetage en C # - E-Book gratuit

Un ManualResetEvent est une variante de AutoResetEvent. Il diffère en ce sens qu'il ne se réinitialise pas automatiquement après la diffusion d'un thread sur un appel WaitOne, et fonctionne donc comme une porte: l'appel Set ouvre la porte, autorisant un nombre illimité de threads en attente à la porte; L'appel de Reset ferme la porte, provoquant potentiellement l'accumulation d'une file de serveurs jusqu'à son ouverture suivante.

On pourrait simuler cette fonctionnalité avec un champ booléen "gateOpen" (déclaré avec le mot-clé volatile) en combinaison avec "spin-sleeping" - vérifiant le drapeau de manière répétée, puis dormant pendant une courte période.

ManualResetEvents est parfois utilisé pour signaler qu'une opération particulière est terminée ou que l'initialisation d'un thread est terminée et qu'il est prêt à effectuer un travail.


34
2017-12-04 07:47



J'ai créé des exemples simples pour clarifier la compréhension de ManualResetEvent vs AutoResetEvent.

AutoResetEvent: Suppose que vous avez 3 threads de travail. Si l'un de ces threads appelle WaitOne (), tous les autres threads arrêteront l'exécution et attendront le signal. Je suppose qu'ils utilisent WaitOne (). C'est comme; si je ne travaille pas, personne ne travaille. Dans le premier exemple, vous pouvez voir que

            autoReset.Set();
            Thread.Sleep(1000);
            autoReset.Set();

Lorsque vous appelez Set (); tous les threads fonctionneront et attendront le signal. Après 1 sec j'envoie le deuxième signal et ils exécutent et attendent (WaitOne ();). Pensez à ces gars-là sont des joueurs de l'équipe de football et si un joueur dit que je vais attendre que le manager m'appelle, et que d'autres attendent que le manager leur dise de continuer (Set ();)

public class AutoResetEventSample
    {
        private AutoResetEvent autoReset = new AutoResetEvent(false);

        public void RunAll()
        {
            new Thread(Worker1).Start();
            new Thread(Worker2).Start();
            new Thread(Worker3).Start();
            autoReset.Set();
            Thread.Sleep(1000);
            autoReset.Set();
            Console.WriteLine("Main thread reached to end.");
        }

        public void Worker1()
        {
            Console.WriteLine("Entered in worker 1");
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Worker1 is running {0}", i);
                Thread.Sleep(2000);
                autoReset.WaitOne();
            }
        }
        public void Worker2()
        {
            Console.WriteLine("Entered in worker 2");

            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Worker2 is running {0}", i);
                Thread.Sleep(2000);
                autoReset.WaitOne();
            }
        }
        public void Worker3()
        {
            Console.WriteLine("Entered in worker 3");

            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Worker3 is running {0}", i);
                Thread.Sleep(2000);
                autoReset.WaitOne();
            }
        }
    }

Dans cet exemple, vous pouvez clairement voir cela lorsque vous appuyez pour la première fois sur Set (); il laissera partir tous les fils, puis après 1 seconde il signale à tous les fils d'attendre! Dès que vous les définissez à nouveau, peu importe qu'ils appellent WaitOne () à l'intérieur, ils continueront à fonctionner car vous devez appeler manuellement Reset () pour les arrêter tous.

            manualReset.Set();
            Thread.Sleep(1000);
            manualReset.Reset();
            Console.WriteLine("Press to release all threads.");
            Console.ReadLine();
            manualReset.Set();

Il s'agit plus de la relation Arbitre / Joueur là-bas, quel que soit le joueur blessé et attendre que les autres continuent à travailler. Si l'arbitre dit attendre (Reset ();), tous les joueurs attendent le signal suivant.

    public class ManualResetEventSample
    {
        private ManualResetEvent manualReset = new ManualResetEvent(false);

        public void RunAll()
        {
            new Thread(Worker1).Start();
            new Thread(Worker2).Start();
            new Thread(Worker3).Start();
            manualReset.Set();
            Thread.Sleep(1000);
            manualReset.Reset();
            Console.WriteLine("Press to release all threads.");
            Console.ReadLine();
            manualReset.Set();
            Console.WriteLine("Main thread reached to end.");
        }

        public void Worker1()
        {
            Console.WriteLine("Entered in worker 1");
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Worker1 is running {0}", i);
                Thread.Sleep(2000);
                manualReset.WaitOne();
            }
        }
        public void Worker2()
        {
            Console.WriteLine("Entered in worker 2");

            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Worker2 is running {0}", i);
                Thread.Sleep(2000);
                manualReset.WaitOne();
            }
        }
        public void Worker3()
        {
            Console.WriteLine("Entered in worker 3");

            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Worker3 is running {0}", i);
                Thread.Sleep(2000);
                manualReset.WaitOne();
            }
        }
    }

17
2017-07-20 19:18



Oui c'est vrai.

Vous pouvez avoir une idée en utilisant ces deux.

Si vous avez besoin de savoir que vous avez terminé avec du travail et que d’autres (threads) en attente peuvent maintenant continuer, vous devez utiliser ManualResetEvent.

Si vous avez besoin d'un accès exclusif mutuel à une ressource, vous devez utiliser AutoResetEvent.


7
2018-04-20 08:48



autoResetEvent.WaitOne() 

est similaire à

try
{
   manualResetEvent.WaitOne();
}
finally
{
   manualResetEvent.Reset();
}

comme une opération atomique


7
2018-06-23 14:37