none
Application Console et Multithreading RRS feed

  • Question

  • Bonjour,

    Voila j'ai besoin de mettre en place une application multithreadée qui se lancera et s'arrêtera automatiquement. Pas besoin d'IHM, la console me semble donc une bonne solution.

    Mon application démarre donc sur une Sub Main, dans celle-ci j'instancie un System.Timers.Timer qui va vérifier la présence de travail à faire et lancer les Threads pour traiter le travail (utilisation de délégués sur le modele du "Prime Number Calculator" de MSDN).

    Toutes les 5 secondes le Timer se lance et alimente les Threads, s'il n'y a plus de travail, le Timer ferme l'application (avec un simple "End", si il y a mieux je suis preneur).

    Le problème est : comment "bloquer" l'exécution de Sub Main pour ne pas que l'application se ferme ? Dans mon Sub Main, une fois le Timer instancié et activé je n'ai plus rien à faire et si je quitte sub Main bien sur l'application se ferme.

    Actuellement je "bloque" avec un Console.ReadKey, j'aimerais savoir s'il existe mieux / plus propre.

    Merci de votre aide !!!
    mardi 10 mars 2009 07:50

Réponses

  • Bonjour, Oui les EventWaitHandle sont aussi simple que ça :-)
    Voila un petit exemple :
    Private m_stopEvent As New ManualResetEvent(False)
    
    Private m_timer As Timer
    
    
    
    Sub Main()
    
      ' start timer
    
      Me.m_timer = New Timer()
    
      Me.m_timer.Start()
    
    
    
      ' wait for stop to be signaled by timer
    
      m_stopEvent.WaitOne()
    
    End Sub
    
    

    En espérant avoir pu vous aider.

    Guillaume
    • Marqué comme réponse MaelstroeM vendredi 10 avril 2009 08:00
    vendredi 10 avril 2009 07:50

Toutes les réponses

  • Bonjour, 

    Le type d'application que tu décris correspond tout à fait à un "Service Windows". Je te conseille donc d'implémenter cette application sous forme de service.

    Pour ce qui est de bloquer le thread principal, tu peux le faire très simplement avec une boucle while qui est vrai jusqu'à ce que, par exemple, les autres threads aient fini leur travail. 

    while (condition qiu attende la fin d'executino des autres threads)
    {
    Thread.Sleep(5000);
    }

    C'est très simple, mais pas très élégant, il y a plus élégant, mais c'est aussi plus compliqué (en utilisant les moniteurs ou en verrouillant l'accès à des objets (lock))

    Bien du plaisir !
    mardi 10 mars 2009 08:32
  • OK je vais regarder du coté des moniteurs par curiosité, entre la boucle While et le ReadKey je préfére le ReadKey.
    Cela pourrait permettre de gérer la saisie de qq paramétres si l'application est démarrée manuellement (sans param de ligne de commande), des choses comme Démarrer - Stopper - Annuller - ou changer le nb max de Thread actifs.

    N'y connaissance rien en Svc Windows j'ai peur que cela me prenne trop de temps, car j'ai vraiment tout a apprendre en la matière.

    Autre petite question :  les accés à Console sont type Thread Safe ? En d'autre therme puis-je faire des Console.WriteLine("Blabla") depuis plusieurs thread sans que cela ne risque de poser de problème (Cross Thread Exception où autre chose de ce genre).

    Merci de ta réponse.
    mardi 10 mars 2009 09:03
  • Comme Loukoum l'a suggéré, un service Windows est fait pour cela, voici un lien  (anglais) expliquant comment faire. Il y a un type de projet qui s'appelle Windows Service.
    Microsoft MVP C# :: mongeon.devrpm.ca
    mardi 10 mars 2009 11:50
    Modérateur
  • Ok merci, je pense que ce sera pour une V2.
    Même si personne ne va passer des heures a regarder l'apli, la console va me suffire pour faire qq opération simple.
    Comme lancer le programme manuellement ect.

    j'ai fini par opter pour qq chose de ce style :

    If args.Length >= 2 AndAlso UCase(args(1)) = "AUTO" Then

        Console.WriteLine("Démarrage en Automatique")

        Action_Start_Timer(False)

    End If

    While True

        Select Case CStr(Console.ReadLine()).ToUpper

            Case "START" : Action_Start_Timer(False)

            Case "FORCE START" : Action_Start_Timer(True)

            Case "STOP" : Action_Stop_Timer()

            Case "CANCEL" : Action_Cancel()

            Case "END"Action_Cancel() : Exit While

            Case Else : Console.WriteLine("Commande inconnue")

        End Select

        Thread.Sleep(0)

    End While

    Si dans le Elapsed du Timer on ne trouve plus de travail alors celui-ci execute un "End" certe pas trés élègant mais efficace.

    Sinon je viens de découvrir "EventWaitHandle" , si j'ai bien compris dans le Sub_Main j'attends avec WaitOne que le Timer signal via Set() qu'il n'y a plus de travaux et donc que je peux quitter l'application ? C'est aussi simple que ça ? Parce que si c'est le cas le problème est réglé.

    Cordialement

    mardi 10 mars 2009 12:40
  • Bonjour, Oui les EventWaitHandle sont aussi simple que ça :-)
    Voila un petit exemple :
    Private m_stopEvent As New ManualResetEvent(False)
    
    Private m_timer As Timer
    
    
    
    Sub Main()
    
      ' start timer
    
      Me.m_timer = New Timer()
    
      Me.m_timer.Start()
    
    
    
      ' wait for stop to be signaled by timer
    
      m_stopEvent.WaitOne()
    
    End Sub
    
    

    En espérant avoir pu vous aider.

    Guillaume
    • Marqué comme réponse MaelstroeM vendredi 10 avril 2009 08:00
    vendredi 10 avril 2009 07:50
  • Ah en v'là une nouvelle qu'elle est bonne :) !

    Oui cela résoud mon problème, enfin cela me conforte dans mon choix car j'ai effectivement opté pour cette solution.

    Merci de votre réponse.
    Cordialement

    vendredi 10 avril 2009 08:07