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 :

Démonstration garantie sans trucage.


Sujet :

Langage Delphi

  1. #1
    Invité
    Invité(e)
    Par défaut Démonstration garantie sans trucage.
    Bonjour.
    Ayant constaté "des choses bizarres" en relation avec l'utilisation de l'instruction "Sleep" dans un projet (de fait, des instructions semblaient s'exécuter dans le désordre), j'ai écrit le programme de test minimum ci-joint (se décompresse dans un dossier "Controle"). Je l'ai compilé avec mon Delphi 6 téléchargé puis installé avec tous les services packs (3, l'un des 2 comprenant 2 parties) puis enregistré chez Embarcadero (j'ai un code d'installation perso de ... 2002) ; la machine est sous Windows 2000 SP4. En analysant le programme, on voit qu'il DEVRAIT attendre l'appui sur la touche "Entrée", afficher une Led bleue, émettre 3 "La" en octave croissante à 1s d'intervalle, puis effacer de nouveau la Led bleue. SAUF ... que la Led n'apparaît jamais ! Gag : si on neutralise l'instruction "Hide" à la fin, on se rend compte que la Led est allumée tout à la fin ! Ceci concerne le prg compilé avec MON Delphi. Je voudrais savoir :
    1) Si ce bug est lié à mon Delphi, autrement dit que quelqu'un essaye de recompiler et de faire les essais.
    2) Sinon, s'il y aurait une forme d'"Hypertreading" là dessous, ce qui serait grave (comme dit, il me semble que d'autres instructions sont permutées également)
    Merci d'avance.
    Fichiers attachés Fichiers attachés

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    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 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Sleep dans le thread principal en plein de milieu d'un OnKeyDown doit bloquer l'écoute des messages Windows

    Si l'on suppose que cela bloques les messages, le Show provoque un SetVisible qui provoque un CM_VISIBLECHANGED (via Perform, celui là utilise directement la WndProc, il doit être géré immédiatement), il invoque InvalidateControl puis un InvalidateRect qui normalement provoque WM_PAINT (et peut être même aussi WM_ERASEBKGND et WM_NCPAINT)

    InvalidateRect lui est une API Windows et donc passe les messages via la file des messages et si on écoute pas ça traite pas
    Contrairement au Perform qui court-circuite le tout !


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    if Key = Entree then
    begin
      beep(444, 100);
      Image_Bleue.Show;
      Image_Bleue.Refresh(); // ou Repaint
      // ou un gros vilain Application.ProcessMessages()
      Sleep(1000);
      beep(888, 100);
      Sleep(1000);
      Image_Bleue.Hide;
      beep(1776, 100);
    end;
    Refresh ou Repaint utilise Perform donc provoque le WM_PAINT immédiat sans passer par la file d'attente !

    Je te conseille plutôt d'utiliser un TTimer ou un event OnIdle qui utilise une TList contenant une sorte de scénario gérant le son et l'image avec une planification !
    En programmation Windows, il ne faut pas bloquer le processus, il faut plutôt une programmation évènementielle ou asynchrone !

    Soit tu codes comme pour un jeu vidéo, ta propre boucle infinie qui ne gère que les messages Windows de base et tu fais tout le reste à la mano
    Et tu as un thread séparé qui gère l'ordonnancement des actions !


    Soit tu utilises la VCL et ses évènements

    En pseudo code (j'ai tapé directement sur le forum, c'est plein de faute, c'est juste pour te donner une idée)


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    if Key = Entree then
    begin
      AddAction(sabeep, 444, 100);
      AddAction(saImage_Bleue, 1);
      AddAction(saSleep, 1000);
      AddAction(sabeep, 888, 100);
      AddAction(saSleep, 1000);
      AddAction(saImage_Bleue, 0);
      AddAction(sabeep, 1776, 100);
     
      Timer1.Interval := 1;
      Timer1.Enabled := True;
    end;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    type
      TScenarioAction = (sabeep, saImage_Bleue, saSleep);
      PScenarioActionItem = ^TScenarioActionItem;
      TScenarioActionItem = record
        AAction: TScenarioAction; 
        P1: integer;
        P2: integer;
        Tick : Cardinal;
      end;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    procedure TForm1.AddAction(AAction: TScenarioAction; P1: integer = 0; P2: integer = 0);
    var
      P: PScenarioActionItem;
    begin
      New(P);
      P^.Action := AAction;
      P^.P1 := P1; 
      P^.P2 := P2; 
      P^.Tick := GetTickCount(); 
      ListAction.Add(P);
    end;
    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 TForm1.Timer1Timer(Sender: TObject);
    var
      I: Integer;
      P: PScenarioActionItem;
      Item: TScenarioActionItem;
    begin
      Timer1.Enabled := False;
     
      for i := 0 to ListAction.count - 1 do
      begin
        P := PScenarioActionItem(List[i]);
        ListAction[i] := nil;
        Item := P^;
        Dispose(P);  
     
        case Item.Action of
          sabeep : Beep(Item.P1, Item.P2)
          saImage_Bleue : saImage_Bleue.Visible := LongBool(Item.P1)
          saSleep : 
          begin
            (*
            if GetTickCount() < Item.Tick + Item.P1
            begin
              ListAction.Pack();
              Timer1.Interval := Item.Tick + Item.P1 - GetTickCount();
              Timer1.Enabled := True;        
              exit;
            end;
            *)
            ListAction.Pack();
            Timer1.Interval := Item.P1;
            Timer1.Enabled := True;        
          end;
      end;
     
      ListAction.Pack();
    end;
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Invité
    Invité(e)
    Par défaut Et problème lié au timer !
    Bonjour.
    Le but de l'opération est en fait de générer une impulsion sur une broche d'un IOWarrior convertisseur USB-> parallèle (non, je ne développe pas un programmateur de composants). Jusqu'à présent j'utilisais la méthode suivante : un timer à 20 ms (en théorie), désactivé, une variable décompteur mise à "n", ma sortie à 1, le timer activé et dans la routine du timer la décrémentation du décompteur, quand il devient <=0 la broche est mise à 0 et le timer désactivé dans la routine. J'ai utilisé cette méthode car je ne savais pas si le timer démarrait avec un cycle plein, l'incertitude sur l'impulsion ne serait alors que de 20ms. Eh, bien, les intervalles générés sont trop longs d'environ 35 à 40 % sur 4s (pour essayer, voir plus loin), idem si je partais d'un cycle de 50ms. Sans commentaire ... Heureusement que mon impulsion a de la marge, entre 800ms et 1,5s ! J'espérais secrètement que Sleep serait plus précis, d'autant que le programme doit être portable au niveau de l'ordinateur et que je comptais utiliser d'autres fonctions plus précises. Raté ! A moins d'utiliser une méthode hyper-lourde qui traîne dans certains bouquins d'électronique.
    Merci quand même pour les tuyaux, je ne ferai plus confiance à Sleep !

  4. #4
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 693
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 693
    Points : 13 128
    Points
    13 128
    Par défaut
    Il faut faire confiance au Sleep, mais pas pour de la synchronisation

    Sleep est une des rares commandes permettant d'influer sur le comportement du(des) processeur(s). Autant un Sleep(100) n'a que peu d'intérêt (justement contrecarrer un problème de synchronisation ou traiter des commandes qui pourraient l'être autrement), autant un Sleep(1) permet de privilégier un autre processus (thread) et nous assurer par la suite une donnée fiable.

  5. #5
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 729
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 729
    Points : 15 132
    Points
    15 132
    Par défaut
    Yop !

    Si tu cherches un timer précis (1 msec), tu fais une recherche avec "delphi precision timer mmsystem", tu trouveras entre autres cette discussion.

    Sais-tu qu'il existe une touche appelée <ENTRÉE> sur ton clavier, censée insérer des retours-chariot dans un pavé de texte totalement imbuvable, histoire de l'aérer ?
    Exemple :
    Citation Envoyé par alberich Voir le message
    Bonjour.

    Le but de l'opération est en fait de générer une impulsion sur une broche d'un IOWarrior convertisseur USB-> parallèle (non, je ne développe pas un programmateur de composants).

    Jusqu'à présent j'utilisais la méthode suivante : un timer à 20 ms (en théorie), désactivé, une variable décompteur mise à "n", ma sortie à 1, le timer activé et dans la routine du timer la décrémentation du décompteur, quand il devient <=0 la broche est mise à 0 et le timer désactivé dans la routine.

    J'ai utilisé cette méthode car je ne savais pas si le timer démarrait avec un cycle plein, l'incertitude sur l'impulsion ne serait alors que de 20ms.
    Eh, bien, les intervalles générés sont trop longs d'environ 35 à 40 % sur 4s (pour essayer, voir plus loin), idem si je partais d'un cycle de 50ms.
    Sans commentaire...

    Heureusement que mon impulsion a de la marge, entre 800ms et 1,5s ! J'espérais secrètement que Sleep serait plus précis, d'autant que le programme doit être portable au niveau de l'ordinateur et que je comptais utiliser d'autres fonctions plus précises. Raté !
    A moins d'utiliser une méthode hyper-lourde qui traîne dans certains bouquins d'électronique.

    Merci quand même pour les tuyaux, je ne ferai plus confiance à Sleep !
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 12/04/2012, 08h18
  2. Comment récupérer le nom du fichier sans l'extension ?
    Par altahir007 dans le forum Langage
    Réponses: 16
    Dernier message: 13/11/2009, 13h20
  3. MDI sans MFC, possible ?
    Par delire8 dans le forum MFC
    Réponses: 4
    Dernier message: 17/06/2002, 07h38
  4. [Kylix] Fiches sans bordure
    Par alex dans le forum EDI
    Réponses: 4
    Dernier message: 28/04/2002, 21h19

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