IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

[thread] Thread Modbus et arrêt (le thread m'a tuer) sur Ubuntu


Sujet :

Python

  1. #1
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 562
    Points : 1 313
    Points
    1 313
    Par défaut [thread] Thread Modbus et arrêt (le thread m'a tuer) sur Ubuntu
    Bonjour,
    toujours mes problèmes de threads
    j'ai bien compris par ailleurs au vu de mes différents post qu'on peut pas les arrêter "brutalement"
    et donc qu'il est souhaitable de leur coller une variable pour les arrêter dans ce style
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class StoppableThread(threading.Thread):
        """Thread class with a stop() method. The thread itself has to check
        regularly for the stopped() condition."""
     
        def __init__(self):
            threading.Thread.__init__(self)
            self._stopper = threading.Event()
     
        def stopit(self):
            self._stopper.set()
     
        def stopped(self):
            return self._stopper.is_set()
     
        def run(self):
            while True:
                if self.stopped():
                    return
                time.sleep(1)
    toutefois la je rencontre un problème étonnant avec un serveur Modbus dans un thread
    voici le code de mon serveur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    import threading
    import logging
    from socketserver import TCPServer,ThreadingMixIn
    from collections import defaultdict
     
    from umodbus import conf
    from umodbus.server.tcp import RequestHandler, get_server
    from umodbus.utils import log_to_stream
    from utils.AppUtilities import StoppableThread, Utilities
     
    class ThreadingServer(ThreadingMixIn, TCPServer):
        pass
     
    class ModbusServer(StoppableThread):
        '''
        Classe permettant la détection et le tracking des camions et voitures.
        '''
        def __init__(self, active = True, Host = 'localhost', Port = '5020'):
            '''
            Constructor
            '''
            StoppableThread.__init__(self)
            log_to_stream(level = logging.DEBUG)
            self.__mutex = threading.Lock()
            self.active = active
     
            # A very simple data store which maps addresss against their values.
            self.__data_store = defaultdict(int)
     
            # Enable values to be signed (default is False).
            conf.SIGNED_VALUES = False
     
            if self.active:
                TCPServer.allow_reuse_address = True
                self.app = get_server(ThreadingServer, (Host, Port), RequestHandler)
     
                @self.app.route(slave_ids = [1], function_codes = [3, 4], addresses = list(range(0, 100)))
                def read_data_store(slave_id, function_code, address):
                    """" Return value of address. """
                    return self.__data_store[address]
     
                @self.app.route(slave_ids = [1], function_codes = [6, 16], addresses = list(range(0, 100)))
                def write_data_store(slave_id, function_code, address, value):
                    """" Set value for address. """
                    with self.__mutex:
                        self.__data_store[address] = value
                        print(self.__data_store)
     
        def setData(self,address,value):
            if self.active:
                with self.__mutex:
                    self.__data_store[address] = value
     
        def getData(self,address):
            if self.active:            
                with self.__mutex :
                    return self.__data_store[address]
     
        def setDataStore(self,value):
            if self.active:
                with self.__mutex:
                    self.__data_store = value
     
        def getDataStore(self):
            if self.active:
                with self.__mutex :
                    return self.__data_store
     
        def stop(self):
            self.app.shutdown()
            self.app.server_close()
     
        def run(self):
            try:
                self.app.serve_forever()
            finally:              
                self.app.shutdown()            
                self.app.server_close()
    j'utilise QModMaster comme client

    bref celui ci se comporte comme un serveur TCP classique
    c'est a dire qu'il doit avoir un accept puis a crée deux threads par client (réception et émission)
    donc quand on fait un shutdown et un close ben les threads clients ne sont pas fermés et donc le programme ne s'arrête pas... évidement si le client se déconnecte ca marche

    voici le code de test de que j'ai fait
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    def testModbusServer(boucle = True):
        print("- TEST MODEBUS ----------------------------------------------")
        ModbusThread = ModbusServer(True, "10.7.58.212", 5020)
        ModbusThread.start()
        #
        print("> pause")
        time.sleep(15)
        #
        print("> fin pause")
        ModbusThread.app.shutdown()
        ModbusThread.app.server_close()
        #
        print("> verification thread")
        while boucle:
            nbThreadRunning = 0       
            for t in threading.enumerate():
                if t.is_alive(): 
                    print(f"thread en cours = {t.getName()}")
                    nbThreadRunning += 1
                    if t.name.startswith("Thread"):                   
                        cc = 0
                        pass
            # arret si il reste seulement MainThread
            if nbThreadRunning <= 1: break;
            time.sleep(1)
        pass
     
    #--------------------------------------------------------------------------------
    # Main
    #--------------------------------------------------------------------------------
    if __name__ == '__main__':
        print("--------------------------------------------------------------")
        print(f" Test ") 
        print("--------------------------------------------------------------")
     
        testModbusServer()
        print("-voila la veritable fin---------------------------------------")
    je me doute que le passage en processus pourrait peut être marcher toutefois les fonction getData et setData serait pas forcement accessible facilement...

    bref est ce que quelqu'un aurait une solution pour que lorsque que l'on shutdown ou close le serveur celui ci ferme toutes les socket qu'il a ouvert et ferme proprement ses threads

    merci
    IKEAS : Finalement je crois que c'est dans ses faiblesses que l'on y trouve a la fois de la force et a la fois de la richesse...
    ----------------------------------------------------
    Si vous avez du taf en wpf & design d'application sympa, contactez moi !!!!
    http://ultimatecorp.eu/wpf/

  2. #2
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 462
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 462
    Points : 9 249
    Points
    9 249
    Billets dans le blog
    6
    Par défaut
    Bonjour

    Sur le plan du principe, un thread déclaré comme "daemon" se supprime tout seul à la fermeture du programme qui l'a créé. cet argument se trouve dans l'appel à Thread de threading.
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  3. #3
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,

    Citation Envoyé par ikeas Voir le message
    bref est ce que quelqu'un aurait une solution pour que lorsque que l'on shutdown ou close le serveur celui ci ferme toutes les socket qu'il a ouvert et ferme proprement ses threads.
    Déjà, il faudrait démontrer que l'appel à app.serve_forever() de la bibliothèque modbus sort bien après l'appel à app.shutdown().

    Par ailleurs, hériter d'une classe nommée StoppableThread en poubélisant la mécanique qu'elle réalise n'apporte rien: juste un code plus compliqué à lire puisqu'on ne comprend pas l'intention.

    Reste la solution de Tyrtamos (par ailleurs documentée) mais à utiliser lorsqu'on ne craint ni corruption ou perte de données.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  4. #4
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 562
    Points : 1 313
    Points
    1 313
    Par défaut
    alors j'ai fait les modifications suivantes :
    - class ModbusServer(threading.Thread): vu que le stoppable thread avait pas d'interet dans ce cas
    - et dans mon test (en rajoutant deux trois trucs + ModbusThread.setDaemon(True))
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    import time
    import os
    import signal
    import sys
    import threading, multiprocessing
    from utils.ModbusUtils import ModbusServer
     
    def testModbusServer(boucle = True):
        print("- TEST MODBUS ------------------------------------------------")    
        ModbusThread = ModbusServer(True, "localhost", 5020)
        ModbusThread.setDaemon(True)
        ModbusThread.start()
        #
        print("> pause")
        print("> set value")
        i = 0
        while i < 30:
            print(f"- value = {i}")
            ModbusThread.setData(1,i)
            i += 1
            time.sleep(1)
        #
        print("> fin pause")
        print("> stop thread")
        ModbusThread.stop()
        print("> del thread")
        del ModbusThread
        print("> fin del thread")
        #
        print("> verification thread")
        while boucle:
            nbThreadRunning = 0       
            for t in threading.enumerate():
                if t.is_alive(): 
                    print(f"thread en cours = {t.getName()}")
                    nbThreadRunning += 1
                    if t.name.startswith("Thread"):                   
                        cc = 0
                        pass
            # arret si il reste seulement MainThread
            if nbThreadRunning <= 1: break;
            time.sleep(1)
        pass
     
    #--------------------------------------------------------------------------------
    # Main
    #--------------------------------------------------------------------------------
    if __name__ == '__main__':
        print("--------------------------------------------------------------")
        print(f" Test CyCounter ") 
        print("--------------------------------------------------------------")   
        testModbusServer(False)
        print("-voila la veritable fin---------------------------------------")
    - et juste pour controler j'ai rajouté ca au run du serveur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def run(self):
            try:
                self.app.serve_forever()
            finally:     
                print("> finally in thread")
                print(">> shutdown")
                self.app.shutdown()            
                print(">> close server")
                self.app.server_close()
                print(">> end finnaly")
    donc on sort toujours pas de l'appli tant que mon QModMaster est connecté
    si on utilise testModbusServer() plutot que testModbusServer(False)
    on peut constater qu'il reste les deux threade créee par le serveur pour la connexion
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    thread en cours = MainThread
    thread en cours = Thread-7
    thread en cours = Thread-8
    ce que je constate c'est que self.app.server_close() semble etre bloquant (enfin parfois)
    dans tous les cas je vois bien le main trhead se terminer mais le programme s'arrete pas
    j'ai tenté tous les arrêts a l'arrache style
    #quit()
    #sys.exit(0)
    #exit(0)
    #raise SystemExit
    #os._exit(0)
    mais le programme se termine que lorsque que ma connexion client se ferme
    IKEAS : Finalement je crois que c'est dans ses faiblesses que l'on y trouve a la fois de la force et a la fois de la richesse...
    ----------------------------------------------------
    Si vous avez du taf en wpf & design d'application sympa, contactez moi !!!!
    http://ultimatecorp.eu/wpf/

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,

    Citation Envoyé par ikeas Voir le message
    donc on sort toujours pas de l'appli tant que mon QModMaster est connecté
    si on utilise testModbusServer() plutot que testModbusServer(False)
    on peut constater qu'il reste les deux threade créee par le serveur pour la connexion
    Tester le côté modbus de la logique serve_forever, shutdown,... devrait se faire, dans un premier temps, sans thread.
    Peut être avec un try...except KeyboardInterrupt (comme on le ferait pour aborter input).

    Puis on avise en fonction du résultat.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  6. #6
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 562
    Points : 1 313
    Points
    1 313
    Par défaut
    j'ai trouvé une solution qui marche mais pas propre du tout
    mais ca arrête effectivement mon soft et évidement ca ferme les connexions clients existantes
    avec
    os.kill(os.getpid(), signal.SIGBREAK)

    je vais essayer la connexion modbus hors thread juste pour voir
    après je pense que la fonction serve_forever est bloquante donc dans le MainThread c'est pas réaliste aussi
    IKEAS : Finalement je crois que c'est dans ses faiblesses que l'on y trouve a la fois de la force et a la fois de la richesse...
    ----------------------------------------------------
    Si vous avez du taf en wpf & design d'application sympa, contactez moi !!!!
    http://ultimatecorp.eu/wpf/

  7. #7
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Citation Envoyé par ikeas Voir le message
    après je pense que la fonction serve_forever est bloquante donc dans le MainThread c'est pas réaliste aussi
    Si on pense que... on teste pour le vérifier. Analyser/comprendre le problème à résoudre est un préalable à la construction d'une solution.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

Discussions similaires

  1. nombre de Threads pour un WCF sur IIS
    Par micky3248 dans le forum IIS
    Réponses: 3
    Dernier message: 25/06/2009, 10h43
  2. Réponses: 5
    Dernier message: 15/06/2007, 15h12
  3. [Thread] Syncronisation et vérrou sur objet
    Par vinzzzz dans le forum Débuter avec Java
    Réponses: 3
    Dernier message: 20/02/2007, 18h45

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo