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

Langage Delphi Discussion :

Programmation Multi Threads


Sujet :

Langage Delphi

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    24
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2006
    Messages : 24
    Points : 10
    Points
    10
    Par défaut Programmation Multi Threads
    Bonjour,

    Je me heurte a un petit problème gênant dans une application multi thread.

    Voici un résumé succinct de ce que l'application est sensée faire :
    1. Lorsque l'utilisateur appuie sur le bouton Start:
    - Un répertoire prédéfini sera monitoré via la classe TDirectoryMonitor (http://www.osnews.com/story/7376/A_D..._Delphi/page1/) et dès qu'une image .tif est ajoutée, un traitement sera effectué sur cette image. (Cf. point 2) Nous appellerons ce répertoire le répertoire INPUT
    - Un répertoire prédéfini sera monitoré via la même classe et dès qu'un fichier .txt est ajouté, un traitement sur ce fichier texte sera effectué. Nous appellerons ce répertoire le répertoire OUTPUT.
    2. Le traitement de l'image se fait via le lancement d'une application en ligne de commande (Via CreateProcess et les info trouvées ici : http://www.developpez.net/forums/d39...uperer-retour/) Les info retournées sur la console par l'application en ligne de commande sont sauvegardées dans un fichier de log. (Contrôlé par une sémaphore) L'application en ligne de commande génère un fichier texte qui sera sauvé dans le répertoire OUTPUT.

    Voici au niveau code comment est structurée l'application :
    FMain (Formulaire principal) lance FMonitoringIput, FMonitoringOutput et FReadConsoleOuput, qui sont tous les 3 des threads.

    Les deux premiers tournent sans problème et réagissent correctement à l'ajout de fichiers. Le problème vient de FReadConsoleOutput. J'ai tenté de le lancer à partir de FMonitoringInput (L'application en ligne de commande se lance lorsqu'il y a un fichier image .tif qui arrive dans INPUT) mais son lancement bloque l'arrivée des messages venant de l'ajout d'un fichier dans INPUT. (Donc si j'ajoute un fichier dans INPUT puis un autre avant que l'application en ligne de commande n'ait fini sont traitement, le message semble perdu et le fichier n'est pas traité)

    J'ai tenté de Mettre FReadConsoleOutput dans FMain et de créer un Stack (Thread Safe) où je push mes infos pour le lancement de l'application en ligne de commande mais ça bloque dès le lancement du thread FReadConsoleOuput qui ne veut pas rendre la main à FMain.

    J'aimerais savoir comment faire pour gérer ce cas de figure, soit, en plus simple :
    App => Thread1 => Thread3 (Tout en permettant à Thread1 de continuer à recevoir des messages et stacker les infos pour le lancement de Thread3 séquentiellement)
    App => Thread2

    J'espère avoir été clair, sinon, n'hésitez pas à demander plus d'info... je bloque vraiment sur ce coup-là et le Delphi est loin d'être mon langage de prédilection.

    Merci d'avance,

    S.

  2. #2
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    24
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2006
    Messages : 24
    Points : 10
    Points
    10
    Par défaut
    En fait, en C#, j'ai la solution pour gérer ce problème =>
    Je crée une Fonction FileAdded qui est appelée lors de l'ajout d'un fichier puis je crée le process pour l'application en ligne de commande et le stocke dans une ProducerConsumerQueue via la méthode EnqueueTask(process) mais je ne vois pas comment simuler ça en Delphi.

    Si quelqu'un peut m'aiguiller, ça serait magnifique.

  3. #3
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 448
    Points
    28 448
    Par défaut
    si j'ai bien compris, tu as 2 thread pour monitorer INPUT et OUTPUT...un événement se déclenche quand un fichier tombe dans un des répertoire...et je suppose que tu es là dans le Thread Principal...il faut donc lancer un Thread secondaire pour executer ton programme en ligne de commande pour que le moniteur reprenne son travail.

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    24
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2006
    Messages : 24
    Points : 10
    Points
    10
    Par défaut
    Ca ressemble à ça, oui...

    En fait, j'ai testé plusieurs solutions :
    1. Mon programme principal lance 3 threads:
    - Monitoring INPUT (Si ajout fichier, ajout d'un appel sur le stack)
    - Monitoring OUTPUT
    - Lecture du stack pour lancer l'application en ligne de commande et lire l'output de la console.

    => L'application bloque au lancement du thread de lecture du stack, il ne rend pas la main au programme principal.

    2. Mon programme principal lance 2 threads:
    - Monitoring INPUT => Si ajout => Lance 1 thread qui lance l'application en ligne de commande et lit l'output de la console
    - Monitoring OUTPUT

    => Monitoring INPUT reste bloqué tant que l'application en ligne de commande n'a pas terminé et ce monitoring ne reçoit plus de message, donc l'ajout de fichiers dans le répertoire pendant ce traitement est ignoré.

    Aucune des deux solution ne semble fonctionner comme je veux.

  5. #5
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 448
    Points
    28 448
    Par défaut
    le problème doit être dans ton code car le propre d'un thread secondaire est de ne pas bloquer le code qui le lance

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    24
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2006
    Messages : 24
    Points : 10
    Points
    10
    Par défaut
    Voilà mon code, pour info:

    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
     
    procedure TReadConsoleThread.CaptureConsoleOutput(ConsoleApp : string);
    const
    	ReadBuffer = 2400;
    var
      SEInfo : TShellExecuteInfo;
      ExitCode : DWORD;
    begin
      WaitForSingleObject(FSemaphoreLog, INFINITE);
      Log('Before Wait In Thread ID ' + IntToStr(Self.ThreadID) + ' - SEM : ' + IntToStr(FSemaphoreRead));
      ReleaseSemaphore(FSemaphoreLog, 1, nil);
      WaitForSingleObject(FSemaphoreRead, INFINITE);
      FillChar(SEInfo, SizeOf(SEInfo), 0);
      SEInfo.cbSize := SizeOf(TShellExecuteInfo);
      With SEInfo Do
      begin
        fMask := SEE_MASK_NOCLOSEPROCESS;
        Wnd := Application.Handle;
        lpFile := PChar(AppPath);
        lpParameters := PChar(Args);
        nShow := SW_SHOWNORMAL;
      end;
      if ShellExecuteEx(@SEInfo) then
      begin
        repeat
          Application.ProcessMessages;
          GetExitCodeProcess(SEInfo.hProcess, ExitCode);
          Log('Exit Code : ' + IntToStr(ExitCode));
        until (ExitCode <> STILL_ACTIVE) or Application.Terminated;
        WaitForSingleObject(FSemaphoreLog, INFINITE);
        Log('After Processing In Thread ID ' + IntToStr(Self.ThreadID));
        ReleaseSemaphore(FSemaphoreLog, 1, nil);
        ReleaseSemaphore(FSemaphoreRead, 1, nil);
        WaitForSingleObject(FSemaphoreLog, INFINITE);
        ReleaseSemaphore(FSemaphoreLog, 1, nil);
      end;
    end;
    Et ça bloque sur la ligne Application.ProcessMessage. Il process bien les message mais avec la Semaphore FSemaphoreRead, il ne la libère jamais donc ça bloque.

    Une idée?

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    24
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2006
    Messages : 24
    Points : 10
    Points
    10
    Par défaut
    Bon, j'ai réussi à faire fonctionner mon application en remplaçant Application.ProcessMessage par un Sleep.

    Le problème, c'est que malgré ça, mon application principale est totalement freezée, d'où je perds l'intérêt d'utiliser des threads... *sic*

    J'ai tenté de jongler avec les priorités mais rien n'y fait.

    Voici le dernier code en date :

    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
    procedure TReadConsoleThread.CaptureConsoleOutput(ConsoleApp : string);
    var
      SEInfo : TShellExecuteInfo;
      ExitCode : DWORD;
    begin
      WaitForSingleObject(FSemaphoreRead, INFINITE);
      FillChar(SEInfo, SizeOf(SEInfo), 0);
      SEInfo.cbSize := SizeOf(TShellExecuteInfo);
      With SEInfo Do
      begin
        fMask := SEE_MASK_NOCLOSEPROCESS;
        Wnd := Application.Handle;
        lpFile := PChar(AppPath);
        lpParameters := PChar(Args);
        nShow := SW_HIDE;
      end;
      if ShellExecuteEx(@SEInfo) then
      begin
        SetThreadPriority(SEInfo.hProcess, THREAD_PRIORITY_LOWEST);
        repeat
          //Application.ProcessMessages;
          Sleep(1000);
          GetExitCodeProcess(SEInfo.hProcess, ExitCode);
        until (ExitCode <> STILL_ACTIVE) or Application.Terminated;
      end;
      ReleaseSemaphore(FSemaphoreRead, 1, nil);
    end;

  8. #8
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 577
    Points : 25 225
    Points
    25 225
    Par défaut
    Pour information, il ne faut JAMAIS faire de Application.ProcessMessages dans un Thread ! cela peut altérer des variables globales du Thread Principal dans un Thread Secondaire, cela pourri tout !

    Tu appeles CaptureConsoleOutput comment ? si c'est dans un thread cela ne devrait pas freezer le Main ... sauf si dans le Main, tu as fait autre une boucle qui attend le relachement du Semaphore, ...

    En général, je fais l'inverse, je lance un thread, et donc à la fin du Execute, je lance une fonction CallBack en Synchronize, ou je passe passe OnTerminate (j'ai vu que bcp de personne on eu des soucis avec) ... et le Main lui ne vérifie rien, il continue sa petite vie, jusqu'à ce que le CallBack soit appelé, ... en général, je n'utilise même pas cette méthode, je mets tous dans des ThreadList d'action, et un Timer dans le Main, regarde la liste régulièrement et regarder les actions en attente, en cours, executer ou en echec ... et dans ton cas faire passer entre chaque Thread par une TThreadList ferait merveille, chaque serait indépendant, le lock étant limité au Add et ponctuellement à un Lock pour le Get (ne pas faire la bétise de locker la liste durant tout le traitement évidemment) ...

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    24
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2006
    Messages : 24
    Points : 10
    Points
    10
    Par défaut
    Merci, je vais creuser dans cette direction.

    Pour info, CaptureConsoleOutput est appelée dans l'Execute du Thread :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    procedure TReadConsoleThread.Execute;
    begin
    	OnTerminate := StopConsoleMonitoring;
    	CaptureConsoleOutput;
    end;
    Qui elle-même est appelée lors de l'ajout d'un fichier dans le répertoire INPUT. (Donc dans un thread indépendant)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    procedure TMonitoringInputThread.StartReadConsoleOutput(CurrentFilename : String);
    begin
      WaitForSingleObject(FSemaphoreLog, INFINITE);
      ReleaseSemaphore(FSemaphoreLog, 1, nil);
      FReadConsoleOutput := TReadConsoleThread.Create(true, 'ReadC');
      WaitForSingleObject(FSemaphoreLog, INFINITE);
      ReleaseSemaphore(FSemaphoreLog, 1, nil);
      FReadConsoleOutput.AppPath := 'C:\Program Files\Eppendorf\epQuantPrime\epQuantPrime.exe';
      FReadConsoleOutput.Args := '"' + FInputFolderToMonitor + '" "' + FOutputFolderToMonitor + '" "' + CurrentFilename + '"';
      FReadConsoleOutput.Priority := tpLower;
      FReadConsoleOutput.Execute;
      WaitForSingleObject(FSemaphoreLog, INFINITE);
      ReleaseSemaphore(FSemaphoreLog, 1, nil);
    end;
    Encore merci,

    S.

  10. #10
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    24
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2006
    Messages : 24
    Points : 10
    Points
    10
    Par défaut
    J'ai l'impression que le Sleep dans le thread ne rend pas la main à l'application principale...pourtant celle-ci n'est nullement liée au thread qui exécute l'application en ligne de commande.

    De plus, le Thread qui lance l'application en ligne de commande semble bien se terminer mais n'exécute jamais ce que j'ai défini dans mon OnTerminate lors de sa création.

  11. #11
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    24
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2006
    Messages : 24
    Points : 10
    Points
    10
    Par défaut
    J'ai trouvé mon problème : fMask := SEE_MASK_NOCLOSEPROCESS; bloquait mon application.

    Merci pour l'aide, la prochaine fois, je creuserais davantage pour l'utilisation de TThreadList.

    Bonne journée,

    S.

  12. #12
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    24
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2006
    Messages : 24
    Points : 10
    Points
    10
    Par défaut
    Ah ben non, retirer le masque retire la synchro entre les thread via le WaitForSingleObject... donc ça ne résous pas mon problème, vu que les threads qui lancent l'application en ligne de commande doivent s'exécuter les uns après les autres...

    Too bad... je continue à creuser.

  13. #13
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    24
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2006
    Messages : 24
    Points : 10
    Points
    10
    Par défaut
    J'ai fait quelques tests supplémentaires, du style virer le createprocess/shellexecuteex et j'ai remplacé tout le contenu de ma fonction par un joli sleep(3000). Et toute mon application freeze pendant 3 secondes par thread lancé...

    J'ai vraiment du mal à comprendre pourquoi, logiquement, le sleep devrait rendre la main à l'application, pourquoi mon form ne répond pas pendant le traitement des threads? Par contre, les messages sont bien traités vu que l'ajout d'images dans le répertoire par la suite est pris en compte et les thread attendent bien sur la semaphore.

    J'ai vraiment du mal à comprendre...

    Pour info, le code qui appelle le thread :

    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
    procedure TMonitoringInputThread.DirChange(Sender: TObject; Action: TDirectoryAction; FileName: String);
    var
    	ext, CurrentFilename: string;
    	processStart, processEnd : TDateTime;
    begin
    	if (Action = daFileAdded) then
    	begin
    		ext := LowerCase(ExtractFileExt(FileName));
    		if (ext = '.eat') then
    		begin
    			processStart := now;
    			CurrentFilename := ExtractFileName(FileName);
    			PostMessage(Self.FParentHandle, WM_UPDATE_UI, 0, 0);
    			processEnd := now;
    			FStatus := 'File added: ' + CurrentFilename + ' in ' + Format('%.3f', [SecondSpan(processStart, processEnd)]) + ' seconds';
    			WaitForSingleObject(FSemaphoreLog, INFINITE);
    			Log(FStatus);
    			ReleaseSemaphore(FSemaphoreLog, 1, nil);
          FReadConsoleOutput := TReadConsoleThread.Create(true, 'ReadC');
          FReadConsoleOutput.AppPath := 'C:\Program Files\Eppendorf\epQuantPrime\epQuantPrime.exe';
          FReadConsoleOutput.Args := '"' + FInputFolderToMonitor + '" "' + FOutputFolderToMonitor + '" "' + CurrentFilename + '"';
          FReadConsoleOutput.Priority := tpLower;
          FReadConsoleOutput.Execute;
    			//frmMain.SetStatusText(FStatus, false);
    		end else
    		begin
    			if (ext <> '.grd') then
    			begin
    				FStatus := 'Incorrect file extension, the file was not processed (' + FileName + ')';
    				WaitForSingleObject(FSemaphoreLog, INFINITE);
    				Log(FStatus);
    				ReleaseSemaphore(FSemaphoreLog, 1, nil);
    				//SetStatusText(FStatus, false);
    			end;
    		end;
    	end;
    end;

  14. #14
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 577
    Points : 25 225
    Points
    25 225
    Par défaut
    Le Sleep bloque le processus en court, mais si ton main, gère une syncrhonisation avec le thread, eh bien, il est bloqué tout autant !

    regarde donc ce code
    TFileSizeList pourrait t'interesser ainsi que le Notify qui surveille en permanence via un Thread et FindFirstChangeNotification

    Tu verras, rien à voir comme façon de procéder ...

  15. #15
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    24
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2006
    Messages : 24
    Points : 10
    Points
    10
    Par défaut
    Je vais jeter un oeil en détail à ton code, merci.

    Je me pose quand même la question, si dans un thread quelconque je veux que les messages soient traités, qu'est-ce que je dois utiliser? WaitForSingleObject avec un timeout de 100 ms par exemple?

    Sinon, ton code fait quoi, dans les grandes lignes? Il lance un thread qui va scanner un répertoire et établir une liste de la taille des fichiers qui s'y trouvent? Le tout en tâche de fond. S'il y a un changement de taille dans l'un des fichiers, un message OnChange est envoyé à l'application... juste?

    Je ne comprends cependant pas le fonctionnement du ReadLastMessages.

    Si dans mon cas je veux repenser mon code en utilisant des messages, du style :
    MainThread lance InputMonitoringThread qui lance X instances de ReadConsoleThread toutes suspendues sauf une (La première ajoutée), et quand elle se termine la suivante est lancée.

    Je ne vois pas comment ReadConsoleThread peut communiquer avec InputMonitoringThread. Un Post/SendMessage est mis dans la MessageQueue de l'application et je ne sais pas comment y accéder à partir de InputMonitoringThread...

  16. #16
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 577
    Points : 25 225
    Points
    25 225
    Par défaut
    Regarde aussi ma fonction CallCmd que je t'ai fournis dans l'autre sujet, qui permet de récupérer la StdOutput de la console DOS en temps réel et cela sans Thread ...

    Après, je n'ai pas tout suivi, mais on peut imaginer que tu lance CallCmd dans un Thread (si c'est indispensable) et que tu donne à TCallCmdEvent, une procedure du thread (via une procédure wrapper intermédiaire) ... ça te montre, surtout comme utiliser les évènements (via objet, ou à l'ancienne via CallBack)

    Et donc tu combines les Deux, le Thread de NotifyFile qui ajoute dans une TThreadList les nouveux fichiers (à la place de ma liste) et un autre thread qui lance CallCmd en lui passant le premier item de la liste (attention à ne pas mettre un lock durant tout le traitement, mais juste à la récupération de l'item), ... les deux tournants parallèlement ...

  17. #17
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    24
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2006
    Messages : 24
    Points : 10
    Points
    10
    Par défaut
    Ben voilà, bonne nouvelle, c'est résolu et ça fonctionne...

    J'ai implémenté un TThreadList et un Timer, comme tu me l'as conseillé et ça marche nickel.

    Je vais jeter un oeil à CallCmd pour voir si je peux améliorer tout ça mais je suis déjà content avec ce que j'ai, tout tourne sans problème.

    En tout cas, un tout grand merci, tu m'as enlevé une fameuse épine du pied!

    Bonne journée,

    S.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Programmation multi-Threads en R sur windows
    Par boris150 dans le forum R
    Réponses: 2
    Dernier message: 12/03/2014, 15h25
  2. [BP7] Multi-cpu, multi-core, multi-thread et programme Pascal
    Par Transgarp dans le forum Turbo Pascal
    Réponses: 6
    Dernier message: 07/04/2008, 18h43
  3. Réponses: 3
    Dernier message: 25/04/2007, 13h21
  4. Programmation Multi-threadée et Synchronisme
    Par ChPortos dans le forum Windows Forms
    Réponses: 2
    Dernier message: 18/04/2007, 11h59
  5. Réponses: 11
    Dernier message: 14/02/2006, 00h26

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