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 :

multiprocessing et QProcess


Sujet :

Python

  1. #21
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Points : 460
    Points
    460
    Par défaut
    Bonjour,

    je me permets de relancer le sujet car j'ai fait pas mal de tests avec les try et except, j'en ai mis dans toutes les fonctions mais rien...

    j'ai testé exception de concurrent.futures mais pas réussis non plus...

    et mis à part ça je pense avoir fait à peu prés tout ce que je voulais

    merci à vous.
    Sous Kubuntu 20.04

  2. #22
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 281
    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 281
    Points : 36 768
    Points
    36 768
    Par défaut
    Citation Envoyé par hizoka Voir le message
    je me permets de relancer le sujet car j'ai fait pas mal de tests avec les try et except, j'en ai mis dans toutes les fonctions mais rien...
    Si on a crée une Dialog box avec un Button "Cancel" écrit dessus, pourquoi s'em... à attraper des Ctrl-C?

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

  3. #23
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Points : 460
    Points
    460
    Par défaut
    parce que cette fameuse fenêtre est facultative :p
    et que c'est soit dans une fenêtre de progression soit dans la console
    Sous Kubuntu 20.04

  4. #24
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 281
    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 281
    Points : 36 768
    Points
    36 768
    Par défaut
    C'est bien joli de vouloir toutes les options possibles mais si vous ne précisez pas le contexte (en postant un code "fonctionnel"), si ce n'est plus une application graphique, vous n'avez plus besoin de Qt et donc une "logique":

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    while True:
         try:
              ...on attend la fin du thread avec un timeout.
              ...if done: break (on sort normalement).
         except KeyboardInterrupt:
              ...on dégage les activités en cours
    ... et voilà...
    devrait fonctionner (sauf à poster un code qui montre que ce n'est pas le cas sous l'environnement X avec la version de Python Z).

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

  5. #25
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Points : 460
    Points
    460
    Par défaut
    Voila mon code épuré :
    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
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    GlobalVar["ProgressDialog"] = ProgressDialog(None)
     
    #############################################################################
    ### Classe gérant la fenetre de progression
    class ProgressDialog(QDialog):
        def __init__(self, Parent=None):
            ### Création de la fenetre de progression.
            ### ...
     
     
            ### Affiche si besoin la fenêtre
            if GlobalVar["GuiLevel"] == 2:
                self.show()
     
     
            ### Conversion des images en textes
            ## Création du thread
            GlobalVar["MonProgressThread"] = ProgressThread()
     
            ## Connexion des signaux de progression et de fin du thread
            GlobalVar["MonProgressThread"].ProgDuThread.connect(self.WorkProgression)
            GlobalVar["MonProgressThread"].FinDuThread.connect(self.Next)
     
            ## Démarrage du thread
            GlobalVar["MonProgressThread"].start()
     
     
     
        #========================================================================
        def WorkProgression(self, value):
            """Fonction de progression de la barre."""
            ### Envoie de la valeur
            self.ProgressBar.setValue(value)
     
     
            ### Force la mise à jour graphique
            QCoreApplication.processEvents()
     
     
     
        #========================================================================
        def Next(self, value):
            """Fonction lancée en fin de conversion des images en textes."""
            ## Fermeture via validation de la fenêtre de progression
            self.accept()
     
            ## ...
     
    #############################################################################
    ### Classe de conversion des images en textes
    class ProgressThread(QThread):
        ### Signaux et variable blo
        ## Création d'un nouveau signal pour informer de la fin du thread
        FinDuThread = pyqtSignal(str)
     
        ## Création d'un nouveau signal pour info du % d'avancement
        ProgDuThread = pyqtSignal(float)
     
     
        #========================================================================
        def __init__(self):
            super().__init__()
     
     
        #========================================================================
        def shutdown(self):
            """Fonction de nettoyage lancée lors de la fermeture de la fenêtre de progression ou de la création d'un fichier Stop."""
            ### Variable bloquante servant aux commandes en cours d'execution
            self.abort = True
     
     
            ### Annulation du travail restant
            for f in GlobalVar["WorkList"]:
                f.cancel()
     
            self.pool.shutdown(wait=True)
     
     
     
        #========================================================================
        def run(self):
            """Fonction lancée lors de l'execution du QThread."""
            ### Création de variables pour le QThread
            ## Valeur de progression
            self.done = 0
     
            ## Variable bloquante
            self.abort = False
     
     
            ### Création de la liste de travail
            GlobalVar["WorkList"] = []
            pool = self.pool = ThreadPoolExecutor(max_workers=QThread.idealThreadCount())
     
     
            ### Remplissage de la liste
            for ImageFile in GlobalVar["SubImgFiles"]:
                ## Chaque commande créée lance la fonction self.Work avec l'argument ImageFile
                future = pool.submit(self.Work, ImageFile)
     
                ## Ajout de la commande à la liste de travail
                GlobalVar["WorkList"].append(future)
     
     
        #========================================================================
        def Work(self, File):
            """Fonction éxécutée pour chaque image à convertir."""
            ### Si la variable bloquante est active, c'est que la fenêtre est fermée ou un fichier stop est présent
            if self.abort:
                return
     
     
            ### ...
     
     
            ## Progression 
            if GlobalVar["GuiLevel"] < 2:
                print(self.done)
            else:
                self.ProgDuThread.emit(self.done)
     
            ### Si c'était le dernier fichier à traiter
            if self.done == MaxValue:
                self.FinDuThread.emit(QCoreApplication.translate("main", "The conversion is finished."))
    La variable GlobalVar["GuiLevel"] permet de savoir s'il faut ou non afficher la fenêtre et donc la façon de faire connaître l'avancement

    Pour faire simple, je créé tout la fenêtre quelque soit le cas mais je l'affiche ou non...
    Sous Kubuntu 20.04

  6. #26
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 281
    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 281
    Points : 36 768
    Points
    36 768
    Par défaut
    Citation Envoyé par hizoka Voir le message
    Voila mon code épuré :
    On ne peut pas faire grand chose avec çà...

    Un code épuré est par exemple comme celui que je vous ai posté tantôt: il fonctionne et on s'attend à y trouver try...except KeyboardInterrupt dedans.

    Par expérience, je ne pense pas qu'il y ait de solution simple à votre problème. Et je ne sais pas si j'aurais le temps de vous montrer comment le poser à défaut de le résoudre.

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

  7. #27
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Si je comprends bien, tu veux arrêter sur demande le travail réalisé par le QThread et les thread de concurrent.futures qu'il a lancé?

    Malheureusement, si j'ai bien compris la notice, les threads de concurrent.futures ne peuvent pas s'arrêter comme ça. En fait, tu es dans une contradiction: tu veux un truc simple et automatique (concurrent.futures), mais tu veux aussi continuer à maîtriser le détail pour remplir des fonctions particulières. J'ai bien peur que ce soit une impasse.

    Si tu tiens vraiment à arrêter sur demande le travail réalisé par les threads qui font le travail, je vois 2 solutions:

    - Au lieu de concurrent.futures, utiliser la solution avec multiprocessing et les queues que j'ai décrites plus haut, mais permettre aux process (ça marcherait aussi avec des threads) qui font le travail, de se suicider si, par exemple, ils n'ont pas trouvé de travail dans la seconde. Il suffirait alors de vider la queue des travaux à réaliser et d'attendre une seconde pour que tout s'arrête.

    - Passer à une solution QThread ou QProcess de PyQt au lieu du multiprocessing de Python, parce que eux peuvent d'arrêter sur demande avec .terminate.

    Cette méthode terminate n'est pas recommandée et constitue un arrêt "sauvage" du travail en cours, mais elle est homogène avec la brutalité d'un "Cle-C"! Pour l'utiliser de temps en temps, je peux témoigner que ça marche, à condition de désactiver juste avant les liens (disconnect) établis correspondant aux signaux, et de ne pas vouloir récupérer les résultats des travaux en-cours qu'on a ainsi arrêté!

    Dans le principe, on doit pouvoir monter un pool de QThread (ou QProcess) qui s'alimentent en travail à une QQueue, et donne le résultat du travail à une autre QQueue, en protégeant les accès à ces 2 queues avec des QMutex.

    Mais bien sûr, c'est un peu plus compliqué que concurrent.futures...
    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

  8. #28
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Points : 460
    Points
    460
    Par défaut
    j'ai testé ça qui fonctionne (pas très propre) mais cela augmente la durée de travail de 25% :
    je lance mon QThread et je fous une boucle qui utilise une variable bloquante... qui se débloque une fois le travail fini...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
            GlobalVar["MonProgressThread"].start()
     
            ## Démarrage du thread
            try:
                while not GlobalVar["Termine"]:
                    pass
     
            except KeyboardInterrupt:
                self.Stop()
    en fait ce qui pose soucis, c'est seulement la récupération de l'info KeyboardInterrupt, le travail en cours, je peux tout arrêter sans problème.

    Pensait vous qu'il aurait moyen de lancer un QThread qui surveille stderr dans son coin (et qui enverrait un message d'arret du taf en cours) sans me bouffer trop de processeur ?

    Si y a rien qui permettrait de faire ce genre de chose, je me pencherais sur ta proposition tyrtamos.

    En tout cas, merci beaucoup à vous pour vos éclairages et vos partages !!

    EDIT :
    avec un sleep de 0.2s à la place du pass, ça semble ok niveau temps de travail
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
            GlobalVar["MonProgressThread"].start()
     
            ## Démarrage du thread
            try:
                while not GlobalVar["Termine"]:
                    slep(0.2)
     
            except KeyboardInterrupt:
                self.Stop()
    Alors évidemment, la boucle ne serait lancé qu'en mode console
    Sous Kubuntu 20.04

  9. #29
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 281
    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 281
    Points : 36 768
    Points
    36 768
    Par défaut
    Salut,

    Toujours dans l'idée de montrer la difficulté, j'ai "arrangé" le bricolage précédent en virant tout ce qui avait trait à Qt en gardant le minimum pour que çà fonctionne lancé depuis la console *et* en y collant le fameux try...except KeyboardInterrupt.
    Ca donne:
    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
    from concurrent.futures import ThreadPoolExecutor as Pool
    import subprocess
    import time
    import sys
     
    class Launcher:
     
        _abort = False            
        _done = False
     
        def __init__(self, count=10):
            self.count = count            
     
        def run_item(self, ident):
            if not self._abort:
                subprocess.call ('python -c "import time; time.sleep(0.5)"')
                return ident
     
        def run(self):
     
            step = 100 / self.count
            done_ratio = 0
     
            def callback(future):
                nonlocal done_ratio
                if not self._abort:
                    done_ratio += step
                    #print('callback', done_ratio, 'ix', future.result())
                    self.on_update(done_ratio)
                    if done_ratio >= 100 :
                        self._done = True
     
            pool = self.pool = Pool(max_workers=2)
            for z in range(self.count):
                future = pool.submit(self.run_item, z)
                future.add_done_callback(callback)    
     
        def shutdown(self):  # ** too much **
            self._abort = True
            self.pool.shutdown(wait=True)
     
        def on_update(self, ratio):
            pass
     
    class ConsoleLauncher(Launcher):
     
        def on_update(self, ratio):
            sys.stdout.write('\r' + '*' * int(ratio/5))
            sys.stdout.flush()
     
     
        def wait(self, delay):
            if not self._done:
                time.sleep(delay)
            return self._done
     
     
    if __name__ == '__main__':        
        launcher = ConsoleLauncher()
     
        launcher.run()  
        while True:
            try:
                if launcher.wait(0.1):
                    break
            except KeyboardInterrupt:
                print('***shutdown***')
                time.sleep(0.01)
                launcher.shutdown()
                break
    çà raconte quoi?
    En mode console, pas besoin de créer un Thread pour ne pas bloquer le GUI. Launcher se gère son pool de threads qui lancent les subprocess.call exécutant une commande externe. ConsoleLauncher "adapte" le Launcher au code principal: la logique est différente puisqu'on lance les différentes tâches, on affiche la progression et on attend que çà se termine ou un CTRL-C.
    Dit autrement, si on veut que ce code sache se lancer avec un GUI ou avec une console, on a des logiques différentes qui s'appuie sur des adaptateurs adhoc qui iront titiller au bout du bout Launcher.
    note: pour sûr, c'est plus compliqué que .show/.hide.
    A partir de là:
    1 - vérifier que ce code fonctionne sur vos OS: je me suis contenté de tester çà sous Windows,
    2 - Je pourrais m'amuser à coder les bouts qui manquent pour le fun (lentement, j'ai plein d'autres truc à faire).
    3 - à explorer: Qt est une bibliothèque pour le programmeur C++ et le programmeur C++ réalise aussi des programmes "console" (i.e. sans le GUI Qt). Donc plutôt qu'avoir un mode console sans Qt et un mode graphique avec Qt, il doit y avoir une ligne médiane à explorer (l'intérêt étant d'avoir quelque chose de plus cohérent et un peu moins de code).

    Citation Envoyé par tyrtamos Voir le message
    Malheureusement, si j'ai bien compris la notice, les threads de concurrent.futures ne peuvent pas s'arrêter comme ça. En fait, tu es dans une contradiction: tu veux un truc simple et automatique (concurrent.futures), mais tu veux aussi continuer à maîtriser le détail pour remplir des fonctions particulières. J'ai bien peur que ce soit une impasse.
    Les exemples que j'ai posté montrent qu'on peut arrêter ce bazar non?
    La question telle que je l'ai comprise est un problème de design: comment avoir des fonctionnalités semblables que l'application soit lancée en mode graphique ou en mode console... C'est pas tellement le code qui est compliqué dans ce cas là mais la définition des différents composants et le rôle/responsabilité qu'on va pouvoir leur attribuer.

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

  10. #30
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 281
    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 281
    Points : 36 768
    Points
    36 768
    Par défaut
    Et voilà...

    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
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    import concurrent.futures as futures
    from concurrent.futures import ThreadPoolExecutor as Pool
    from PyQt5.QtCore import QObject, pyqtSignal
     
    class Launcher(QObject):
     
        update_done_ratio = pyqtSignal(float)
        finished = pyqtSignal()
     
        def __init__(self, parent=None, max_workers=2):
            super().__init__(parent)
            self.pending_fs = set()
            self.done_fs = set()
            self.pool = Pool(max_workers=max_workers)     
            self.finished.connect(lambda: self.pool.shutdown(wait=True))
     
        def fs_callback(self, fs):
            self.pending_fs.remove(fs)
            self.done_fs.add(fs)
            done = len(self.done_fs)
            left = len(self.pending_fs)
            self.update_done_ratio.emit(done / (done + left)) 
            if not self.pending_fs:
                self.finished.emit()
     
        def submit(self, func):
            fs = self.pool.submit(func)
            self.pending_fs.add(fs)
            fs.add_done_callback(self.fs_callback)
            return fs
     
        def abort(self):
            for fs in self.pending_fs.copy():
                fs.cancel()
     
    def console_app(argv, iterfunc=None):
     
        import sys
        import signal
        import time
     
        from PyQt5.QtCore import QCoreApplication
     
        class Helper(Launcher):
            def __init__(self, max_workers=2):
                super().__init__(max_workers=max_workers)
                self.update_done_ratio.connect(self.update)    
                self.finished.connect(app.quit)  
                signal.signal(signal.SIGINT, self.signal_handler) 
     
            def update(self, ratio):
                size = 50
                sys.stdout.write('\r' + '%-*s|(%2.1f)' % (
                                    size, '*' * int(ratio * size), ratio * 100))
                sys.stdout.flush()
     
            def signal_handler(self, signal, frame):
                time.sleep(0.1)
                print ('ctrl-C')
                self.abort() 
     
        app = QCoreApplication([])
     
        launcher = Helper()
     
        for func in iterfunc:
            launcher.submit(func)
     
        app.exec_()
     
    def qt_app(argv, iterfunc=None):
     
        from PyQt5.QtWidgets import QApplication, QProgressDialog, QPushButton
     
     
        def do_launch(functions):
            launcher = Launcher()
            dialog = QProgressDialog("En cours...", "Annuler", 0, 100)
            launcher.update_done_ratio.connect(lambda x: dialog.setValue(100*x))
            launcher.finished.connect(dialog.reset) 
     
            for func in functions:
                launcher.submit(func)
     
            dialog.exec_()           
     
        app = QApplication([])
        functions = list(iterfunc) # histoire de pouvoir faire X start    
        btn = QPushButton('start')
        btn.clicked.connect(lambda: do_launch(functions))
        btn.show()
     
        exit(app.exec_())
     
     
    if __name__ == '__main__':
        import time
        import sys
     
        COUNT = 10    
     
        def gen_func():
            def task(x):
                time.sleep(1)
                return(x)
            for z in range(COUNT):
                yield lambda x=z: task(x)
     
        if len(sys.argv) > 1:
            console_app([], iterfunc=gen_func())
        else:
            qt_app([], iterfunc=gen_func())
    Dans cette mouture, le Launcher est un QObject qui permet d'adapter concurrent.futures aux besoins. Les différentes portions ont été pensées modules mais écrits sous la forme de fonctions (avec des imports qui traînent dans les premières instructions).

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

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 2 PremièrePremière 12

Discussions similaires

  1. MPTL: MultiProcessing Template Library
    Par alskaar dans le forum Langage
    Réponses: 16
    Dernier message: 29/04/2007, 16h44
  2. Réponses: 8
    Dernier message: 21/12/2006, 21h03
  3. Langage pour contrôle multiprocessing
    Par crocodile dans le forum Langages de programmation
    Réponses: 4
    Dernier message: 13/06/2006, 20h02
  4. lock de fichier - multiprocess
    Par hugo123 dans le forum Entrée/Sortie
    Réponses: 5
    Dernier message: 11/04/2006, 10h08
  5. Réponses: 16
    Dernier message: 30/01/2004, 11h05

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