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

Threads & Processus C++ Discussion :

[debutant] DLL et Threads asynchrone


Sujet :

Threads & Processus C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Expert confirmé
    Avatar de Auteur
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    7 660
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 7 660
    Par défaut [debutant] DLL et Threads asynchrone
    bonjour,

    depuis un programme externe j'appelle une fonction de ma DLL :
    Code c++ : 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
     
    void DLL_EXPORT initNI(long aN, long aDuration, long aDelta, long aCode)
    {
        static DWORD threadID;
        static HANDLE  hThread;
        static paramPort *param;
     
        param = new paramPort;
     
        param->dtPulse = aDelta;
        param->nbPulse = aN;
        param->pulseDuration = aDuration;
        param->value = aCode;
     
        hThread = CreateThread(NULL, 0, sentPulse, param, 0, &threadID);
     
        WaitForSingleObject(hThread, 1);
        CloseHandle(hThread);
     
        delete param;
    }


    Cette fonction crée un thread qui me permet ensuite d'envoyer un pulse sur une ligne d'une carte NI.

    Cette fonction peut-être appelée à tout moment et cela me permet d'envoyer des pulses sur n'importe quelle ligne de ma carte NI de manière asynchrone.

    Deux problèmes se posent :
    1- ma fonction sentPulse ne reçoit pas toujours les bons paramètres, ils sont parfois "perdus" (c'est pour cette raison que j'ai des variables statiques, mais ça ne change rien) ;

    2- je ne peut pas mettre
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    WaitForSingleObject(hThread, INFINITE);
    sinon mon thread devient bloquant et je ne veux pas car je ne peux pas envoyer d'autres pulses tant que le thread n'est pas fini


    => Comment je peux transmettre mes données à ma fonction sans les perdre ?
    => ensuite comment je peux créer de manière asynchrone mes threads et détruire proprement mes thread ?


    [edit]

    ma structure paramPort est définie comme ceci :
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    typedef struct
    {
        long pulseDuration;
        long dtPulse;
        long nbPulse;
        long value;
    }paramPort;
    [/edit]

  2. #2
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Bonjour,
    Citation Envoyé par Auteur Voir le message
    1- ma fonction sentPulse ne reçoit pas toujours les bons paramètres, ils sont parfois "perdus" (c'est pour cette raison que j'ai des variables statiques, mais ça ne change rien) ;
    Passer en statique n'a aucun impact sur les signaux perdus et met le b..del dans ta fonction. Les pulses ne seraient-ils pas perdus parce que ta carte les manque ? Ou alors tu utilises un sleep pour gérer tes ticks ?
    Citation Envoyé par Auteur Voir le message
    => Comment je peux transmettre mes données à ma fonction sans les perdre ?
    trouver la cause de la perte. Problème de priorité des threads ? Sleep pour endormir le thread entre 2 ticks ?
    Citation Envoyé par Auteur Voir le message
    => ensuite comment je peux créer de manière asynchrone mes threads et détruire proprement mes thread ?
    En n'utilisant pas de variables statiques, en passant tous les paramètres à ton thread, en ne faisant pas de WaitForSingleObject/CloseHandle.

    Ca donnerait quelque chose comme ça :
    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
     
    void DLL_EXPORT initNI(long aN, long aDuration, long aDelta, long aCode)
    {
        DWORD threadID;
        HANDLE  hThread;
        paramPort *param;
     
        param = new paramPort;
     
        param->dtPulse = aDelta;
        param->nbPulse = aN;
        param->pulseDuration = aDuration;
        param->value = aCode;
     
        hThread = CreateThread(NULL, 0, sentPulse, param, 0, &threadID);
    }
     
    DWORD WINAPI sentPulse(LPVOID lpParameter)
    {
       paramPort *param = reinterpret_cast<paramPort *>(lpParameter);
       while(do_my_job)
       {
       }
       delete lpParameter;
    }
    Le thread est automatiquement détruit en quittant la fonction sendPulse. Pas besoin de faire explicitement de closeHandle.

    Si tu veux pouvoir arrêter ton thread à partir du thread principal alors il faut que initNI retourne le handle du thread et/ou le thread ID et mettre un mécanisme d'échange entre les deux.

    Accessoirement, pourquoi ne pas encapsuler le tout par une classe qui va bien ?

  3. #3
    Expert confirmé
    Avatar de Auteur
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    7 660
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 7 660
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Passer en statique n'a aucun impact sur les signaux perdus et met le b..del dans ta fonction. Les pulses ne seraient-ils pas perdus parce que ta carte les manque ? Ou alors tu utilises un sleep pour gérer tes ticks ?
    Effectivement, pour passer de l'état 1 à 0 j'ai une horloge. Mais je n'utilise pas la fonction Sleep() mais une boucle while() (plus précis dans mon cas et j'ai vu que Sleep créait justement un thread) :

    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    // fonction pour mettre à 1 la ligne choisie
     cpuTime = clock() + pulseDuration;
    while (clock() <= cpuTime){}
    // fonction pour mettre à 0 la ligne choisie

    Ensuite pour les pulses perdus, je ne sais pas si cela vient de la carte ou du programme, je vais déjà corriger le programme


    Citation Envoyé par 3DArchi Voir le message
    Sleep pour endormir le thread entre 2 ticks ?
    Je n'avais pas penser à endormir le thread entre 2 états mais je me demande si c'est une bonne solution ?



    Citation Envoyé par 3DArchi Voir le message
    Problème de priorité des threads ?
    Donc la perte d'information pourrait aussi venir de la priorité des threads...Tu peux être plus précis ?

    Citation Envoyé par 3DArchi Voir le message
    Le thread est automatiquement détruit en quittant la fonction sendPulse. Pas besoin de faire explicitement de closeHandle.
    Je croyais que le closeHandle était obligatoire, je vais donc le supprimer, peut-être que ça résoudra une partie du problème.
    Je vais également supprimer les variables statiques.



    Citation Envoyé par 3DArchi Voir le message
    Accessoirement, pourquoi ne pas encapsuler le tout par une classe qui va bien ?
    euh comment ferais-tu ? Car je ne vois pas trop comment accéder aux méthodes d'une classe par une DLL

  4. #4
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par Auteur Voir le message
    euh comment ferais-tu ? Car je ne vois pas trop comment accéder aux méthodes d'une classe par une DLL
    En exportant la classe et non une fonction (si ta DLL est utilisée par une appli avec le même compilateur).

  5. #5
    Expert confirmé
    Avatar de Auteur
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    7 660
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 7 660
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    En exportant la classe et non une fonction (si ta DLL est utilisée par une appli avec le même compilateur).
    la DLL est appelée à partir de matlab, donc je doute que je puisse exporter une classe.

    Je n'ai pas remarqué tout de suite :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    DWORD WINAPI sentPulse(LPVOID lpParameter)
    {
       paramPort *param = reinterpret_cast<paramPort *>(lpParameter);
       while(do_my_job)
       {
       }
       delete lpParameter;
    }
    tu fais le delete lpParameter dans la fonction threadée pas dans la fonction qui crée le thread. Mes pertes de données viennent peut-être de là...


    [edit]
    le delete sur lpParameter provoque un warning :
    |186|warning: deleting `void*' is undefined|
    [/edit]

  6. #6
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Ou plus simple: Tu fermes le handle immédiatement, sans attendre la fin du thread.
    Va falloir que je révise j'ai l'impression d'avoir oublié mes bases

    Citation Envoyé par Auteur Voir le message
    la DLL est appelée à partir de matlab, donc je doute que je puisse exporter une classe.
    Je ne sais pas. Faudrait demander aux pro Matlab si ça s'interface avec C++ ?
    Citation Envoyé par Auteur Voir le message
    Je n'ai pas remarqué tout de suite :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    DWORD WINAPI sentPulse(LPVOID lpParameter)
    {
       paramPort *param = reinterpret_cast<paramPort *>(lpParameter);
       while(do_my_job)
       {
       }
       delete lpParameter;
    }
    tu fais le delete lpParameter dans la fonction threadée pas dans la fonction qui crée le thread. Mes pertes de données viennent peut-être de là...
    Le delete est à faire quand la fonction se termine. Donc le thread n'utilise plus les paramètres. Donc les pertes de données ne peuvent venir de là.

    Citation Envoyé par Auteur Voir le message
    [edit]
    le delete sur lpParameter provoque un warning :

    [/edit]
    YAMA trompé :Ensuite revenons au problème :
    0/ Quelles sont tes valeurs de fréquences ?
    1/ Le thread est-il de type 'fire-and-forget' ou alors tu dois pouvoir l'arrêter, le (re)configurer depuis matlab ?
    2/ Ne pas utiliser de sleep dans ton thread car effectivement tu perds en précision. Pour l'instant, il ne me vient pas d'autres idées que l'attente active que tu as mise en oeuvre. Ca occupe certes le processeur, mais effectivement, c'est plus précis. Si ta fonction ne fait vraiment que ça : une boucle d'attente active, puis émission du signal, alors la perte du signal peut avoir différentes causes :
    1/ priorité trop faible donc le thread n'est pas 'assez' ordonnancé et il loupe des émissions ;
    2/ trop de thread en même temps : comme ils font une attente active, il est possible qu'il ne soit pas ordonnancé à temps et loupent une émission.
    Peut-être ta granularité est-elle trop fine ?

  7. #7
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Le thread est automatiquement détruit en quittant la fonction sendPulse. Pas besoin de faire explicitement de closeHandle.
    Si c'était vrai, cela causerait une race condition avec WaitForSingleObject().

    @Auteur: N'écoute pas les mauvais conseils et remets le CloseHandle().
    De plus, ton thread fait appel à la CRT (ici, ::operator delete), donc tu devrais utiliser _beginthreadex().
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Si c'était vrai, cela causerait une race condition avec WaitForSingleObject().
    Effectivement, pour le close handle, j'ai parlé trop vite :
    Citation Envoyé par MSDN
    The thread object remains in the system until the thread has terminated and all handles to it have been closed through a call to CloseHandle.
    Ce qui est sur c'est qu'à la fin de la fonction, le thread est terminé.
    En revanche, pas forcément besoin de se mettre en attente de la fin du thread pour fermer le handle. Soit un polling sur l'état du thread, soit une notification explicite du thread (via un msg) quand il se termine.

  9. #9
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    En revanche, pas forcément besoin de se mettre en attente de la fin du thread pour fermer le handle. Soit un polling sur l'état du thread, soit une notification explicite du thread (via un msg) quand il se termine.
    Ou plus simple: Tu fermes le handle immédiatement, sans attendre la fin du thread.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

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

Discussions similaires

  1. [debutant] Utilisation des threads ou pas ?
    Par remsrock dans le forum C#
    Réponses: 3
    Dernier message: 17/09/2008, 14h32
  2. Utilisation des dll et threads
    Par ppfromero dans le forum C
    Réponses: 14
    Dernier message: 30/06/2008, 09h31
  3. [debutant] Prob avec threads ! :(:(
    Par little pepito dans le forum Concurrence et multi-thread
    Réponses: 3
    Dernier message: 09/05/2007, 17h26
  4. DLL et Thread
    Par rvzip64 dans le forum Delphi
    Réponses: 1
    Dernier message: 09/10/2006, 13h23
  5. Threads asynchrones...
    Par zitoune92 dans le forum Delphi
    Réponses: 5
    Dernier message: 15/05/2006, 20h41

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