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++

  1. #1
    Expert éminent sénior
    Avatar de Auteur
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    7 655
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 7 655
    Points : 11 150
    Points
    11 150
    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
    Points : 13 017
    Points
    13 017
    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 éminent sénior
    Avatar de Auteur
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    7 655
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 7 655
    Points : 11 150
    Points
    11 150
    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
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 589
    Points
    41 589
    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().

  5. #5
    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
    Points : 13 017
    Points
    13 017
    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.

  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
    Points : 13 017
    Points
    13 017
    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).

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 382
    Points : 41 589
    Points
    41 589
    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.

  8. #8
    Expert éminent sénior
    Avatar de Auteur
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    7 655
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 7 655
    Points : 11 150
    Points
    11 150
    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]

  9. #9
    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
    Points : 13 017
    Points
    13 017
    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 ?

  10. #10
    Expert éminent sénior
    Avatar de Auteur
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    7 655
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 7 655
    Points : 11 150
    Points
    11 150
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    YAMA trompé :
    j'ai corrigé

    Citation Envoyé par 3DArchi Voir le message
    Ensuite revenons au problème :
    0/ Quelles sont tes valeurs de fréquences ?
    les pulses sont "brefs" (enfin tout est relatif )
    minimum 2ms et au plus 1 seconde

    Citation Envoyé par 3DArchi Voir le message
    1/ Le thread est-il de type 'fire-and-forget' ou alors tu dois pouvoir l'arrêter, le (re)configurer depuis matlab ?
    je ne connais pas le terme "fire-and-forget" mais je pense avoir compris ta pensée : dès que le thread est créé, le pulse doit-être émis, il doit s'arrêter de lui même (= aller jusqu'à la fin de la fonction).

    Donc si je n'ai pas accès après sa création ce n'est pas grave. Les paramètres sont donnés dès la création du thread et on n'y touche plus jusqu'à ce qu'il se termine.


    Citation Envoyé par 3DArchi Voir le message
    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.
    Tu avais suggéré d'endormir le thread... Mais je crois que cela va nécessiter des sémaphores, non ? (j'ai oublié un peu les concepts des thread moi aussi )

    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 ?
    1) Les thread créés doivent tous avoir la même priorité. En tout cas ils doivent s'exécuter dans l'ordre où ils sont créés.
    2)Au maximum j'envoie 4 pulses simultanés.


    Là je vais relancer le programme pour voir si je perds à nouveau des informations.

  11. #11
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Je pense que tu aurais tout intérêt à lancer N threads de traitement (4 apparemment pour toi) simultanément, à les bloquer en attente d'une action à faire et de les réveiller sur réception d'une structure de pulse à générer. Ce serait plus efficace en ressources, et cela diminuerait la latence entre l'ordre et la génération effective.

  12. #12
    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
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par Auteur Voir le message
    Tu avais suggéré d'endormir le thread...
    Non, non. On s'était mal compris. Ce que je voulais dire c'est que l'utilisation de sleep pouvait expliquer ton problème. Mais il ne faut surtout pas l'utiliser si tu dois avoir une précision assez fine.
    Citation Envoyé par Auteur Voir le message
    Mais je crois que cela va nécessiter des sémaphores, non ?
    En mettant en oeuvre la solution de Mac LAK (lancement simultanée des 4 threads) effectivement, le sémaphore te permet d'attendre la fin des 4 en même temps. Mais ce n'est pas obligatoire avec windows où WaitForMultipleObjects avec bWaitAll à vraie te permet de tous les attendre.

  13. #13
    Expert éminent sénior
    Avatar de Auteur
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    7 655
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 7 655
    Points : 11 150
    Points
    11 150
    Par défaut
    Citation Envoyé par Mac LAK Voir le message
    Je pense que tu aurais tout intérêt à lancer N threads de traitement (4 apparemment pour toi) simultanément, à les bloquer en attente d'une action à faire et de les réveiller sur réception d'une structure de pulse à générer. Ce serait plus efficace en ressources, et cela diminuerait la latence entre l'ordre et la génération effective.
    Citation Envoyé par 3DArchi Voir le message
    En mettant en oeuvre la solution de Mac LAK (lancement simultanée des 4 threads) effectivement, le sémaphore te permet d'attendre la fin des 4 en même temps. Mais ce n'est pas obligatoire avec windows où WaitForMultipleObjects avec bWaitAll à vraie te permet de tous les attendre.
    euh attention : les threads ne partent pas en même et ne se terminent pas en même temps. Il est donc hors de question de les attendre.

    En plus je constate que je me suis mal exprimé : je vais utiliser 4 lignes pour envoyer mes pulses, mais je ne vais pas forcément créer 4 thread. Je crée un thread chaque fois que je dois envoyer un pulse sur une ligne définie : si je dois envoyer 50 pulses de 2ms sur ma ligne 1 à divers intervalles de temps (intervalles >> 2ms), je vais devoirs créer 50 threads (sachant que je ne vais pas créer de nouveau thread tant que le pulse n'est pas parti).


    Ou alors gérer autrement mes threads :
    créer autant de thread que nécessaire, puis les réveiller si j'ai besoin d'envoyer un pulse et les endormir lorsque je n'ai plus besoin d'eux. Enfin les détruire lorsque je quitte mon programme.

  14. #14
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par Auteur Voir le message
    euh attention : les threads ne partent pas en même et ne se terminent pas en même temps. Il est donc hors de question de les attendre.
    J'avais bien compris. Un thread par ligne physique, si tu émets sur la ligne 1, les trois autres restent à roupiller tranquillement et seul le premier thread est réveillé.

    Citation Envoyé par Auteur Voir le message
    En plus je constate que je me suis mal exprimé
    Non, du moins pas pour moi. J'avais bien compris ça dans ce sens, et c'est là que je te dis justement qu'un thread en attente sur une FIFO (le thread s'endort s'il n'a plus de boulot, mais reste créé) est bien plus efficace. Ils ne seront détruits qu'en fin d'application.

  15. #15
    Expert éminent sénior
    Avatar de Auteur
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    7 655
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 7 655
    Points : 11 150
    Points
    11 150
    Par défaut
    J'ai donc relancé mon programme, je récupère tous mes événements (en tout cas beaucoup plus après ces corrections ).

    Par contre, mon horloge et sa boucle while ce n'est pas terrible, la précision est minable : pour un temps de 2ms la durée réelle varie entre 2 et 6ms voire plus.

    Je vais donc utiliser QueryPerformanceFrequency et QueryPerformanceCounter en espérant avoir quelque chose de bien meilleur (je ferai le test lundi)



    Citation Envoyé par Mac LAK Voir le message
    J'avais bien compris ça dans ce sens, et c'est là que je te dis justement qu'un thread en attente sur une FIFO (le thread s'endort s'il n'a plus de boulot, mais reste créé) est bien plus efficace. Ils ne seront détruits qu'en fin d'application.
    tu pourrais me poster un exemple, pour que je vois comment
    1- Tu ferais ta pile de thread (sans doute une boucle dans laquelle tu stockes dans un tableau les handle des threads)
    2- Comment tu les mets en attente d'une instruction
    3- Tu réveilles le thread
    4- Comment tu le remets en attente (sans prendre de temps CPU si possible)

  16. #16
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par Auteur Voir le message
    Tu ferais ta pile de thread (sans doute une boucle dans laquelle tu stockes dans un tableau les handle des threads)
    Vu que tu es en C++ et qu'à ce stade d'initialisation, les perfs ne sont pas critiques, directement un std::vector de HANDLE sur les threads ou de DWORD (Threads ID).
    Pour faire un peu plus propre, autant mettre dans ce vecteur tous les éléments partagés / exportés par le thread, notamment la FIFO (std::queue), le sémaphore / event, le mutex requis par la synchronisation et tous les autres éléments d'initialisation de ton thread. Tu lui passera l'adresse de la structure associée en paramètre de création, structure qui sera donc contenue dans le vector.

    Citation Envoyé par Auteur Voir le message
    2- Comment tu les mets en attente d'une instruction
    WaitForSingleObject sur un sémaphore, tout simplement. Ensuite, le thread va prendre un mutex associé à la FIFO, récupérer l'élément de tête, lâcher le mutex et va faire ça tant qu'il reste des éléments dans la FIFO (size() non nul).
    De même, le thread principal va prendre le mutex, pousser un élément dans la FIFO, lâcher le mutex et signaler le sémaphore / event pour réveiller le thread si size() valait 0 avant l'insertion de l'item.

    Citation Envoyé par Auteur Voir le message
    3- Tu réveilles le thread
    Via SetEvent si tu as utilisé un event, ou via ReleaseSemaphore si tu as préféré un sémaphore.

    Citation Envoyé par Auteur Voir le message
    4- Comment tu le remets en attente (sans prendre de temps CPU si possible)
    C'est WaitForSingleObject (appliqué au sémaphore ou à l'event) qui met le thread en sommeil, jusqu'à ce que l'objet de synchronisation sur lequel tu attends soit signalé / activé.


    Tu as des exemples d'utilisation de tout ça sur MSDN, via les liens de fonctions que je t'ai mis.

  17. #17
    Expert éminent sénior
    Avatar de Auteur
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    7 655
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 7 655
    Points : 11 150
    Points
    11 150
    Par défaut
    Je vois à peu près comment faire...

    Mais de toute manière je suis obligé de faire une attente active pour passer ma ligne de l'état haut à l'état bas ?

  18. #18
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par Auteur Voir le message
    Mais de toute manière je suis obligé de faire une attente active pour passer ma ligne de l'état haut à l'état bas ?
    Sur un OS non-temps réel, c'est effectivement préférable, mais tu peux toujours avoir des aléas malgré tout. C'est l'attente des ordres eux-mêmes qui ne sera PAS active, quel que soit le cas de figure choisi pour gérer les durées des signaux.

    Autre solution, qui devrait normalement être fiable et que je t'encourage à essayer : passer tes threads de travail en priorité maximale (THREAD_PRIORITY_TIME_CRITICAL), et utiliser un timer système (SetWaitableTimer) pour gérer tes attentes. Il faudra vérifier que c'est correct en terme de timing, bien entendu, via un QueryPerformanceCounter, mais avec un thread en très haute priorité cela devrait être le cas.

    N'utilise SURTOUT PAS la fonction SetTimer, qui fonctionne via les messages Windows. La précision est de l'ordre de 10 à 20 ms au mieux, donc inutilisable pour ton besoin.


    Attention : N'utilise JAMAIS la priorité TIME_CRITICAL sur un thread que tu n'as pas correctement testé, notamment pour vérifier que tu arrives bien à l'arrêter et qu'il ne boucle pas en bouffant tout le CPU disponible. Notamment, je t'encourage à ne jamais autoriser cette valeur de priorité en mode Debug (test "#ifdef _DEBUG" par exemple).
    Si jamais tu as un thread hors de contrôle avec cette priorité, tu vas geler ta machine et seul un reboot violent te permettra de reprendre la main.
    Donc, teste ton thread en haute priorité (mais pas maximale), quitte à avoir des timings peu précis. Une fois le principe général validé, notamment les cas d'erreur, et UNIQUEMENT après ces tests, vérifie les timings en priorité maximale.

  19. #19
    Expert éminent sénior
    Avatar de Auteur
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    7 655
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 7 655
    Points : 11 150
    Points
    11 150
    Par défaut
    Citation Envoyé par Mac LAK Voir le message
    Sur un OS non-temps réel, c'est effectivement préférable, mais tu peux toujours avoir des aléas malgré tout. C'est l'attente des ordres eux-mêmes qui ne sera PAS active, quel que soit le cas de figure choisi pour gérer les durées des signaux.
    Mes premiers tests ont montré que la combinaison de QueryPerformanceFrequency() et QueryPerformanceCounter() donnent de bien meilleurs résultats que Sleep ou clock(). C'est déjà ça. J'ai même été surpris du résultat


    Citation Envoyé par Mac LAK Voir le message
    Autre solution, qui devrait normalement être fiable et que je t'encourage à essayer : passer tes threads de travail en priorité maximale (THREAD_PRIORITY_TIME_CRITICAL), et utiliser un timer système (SetWaitableTimer) pour gérer tes attentes. Il faudra vérifier que c'est correct en terme de timing, bien entendu, via un QueryPerformanceCounter, mais avec un thread en très haute priorité cela devrait être le cas.
    Franchement je ne souhaite pas utiliser la priorité maximale pour ces threads pour plusieurs raisons :
    - je dois également gérer le clavier et la souris : en priorité maximale, je vais perdre des informations
    - j'ai également des animations : je risque d'avoir de sacrés ralentissements.

    En plus l'application qui appellera cette DLL tourne déjà en utilisant la priorité maximale.

    Citation Envoyé par Mac LAK Voir le message
    N'utilise SURTOUT PAS la fonction SetTimer, qui fonctionne via les messages Windows. La précision est de l'ordre de 10 à 20 ms au mieux, donc inutilisable pour ton besoin.
    il ne m'est pas venu à l'esprit d'utiliser cette fonction

  20. #20
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par Auteur Voir le message
    - je dois également gérer le clavier et la souris : en priorité maximale, je vais perdre des informations
    Non, parce que ton thread ne travaille finalement que très très peu : lors de la prise de données depuis la FIFO, et lors des appels au WaitableTimer. Le reste du temps, il est endormi et dans ce cas, peu importe sa priorité.

    Citation Envoyé par Auteur Voir le message
    - j'ai également des animations : je risque d'avoir de sacrés ralentissements.
    Non plus. La charge réelle de tes threads sera en fait ridicule, la priorité ne visant dans ce cas QUE à les rendre prioritaires au sein de l'OS, donc plus réactifs. Mais comme ils passent la majeure partie de leur temps endormis à attendre un event, ils consomment très peu de temps CPU au final.
    Bien sûr, il faut absolument utiliser un timer dans ce cas et non plus une attente active, sinon ça va faire assez mal.

    Citation Envoyé par Auteur Voir le message
    En plus l'application qui appellera cette DLL tourne déjà en utilisant la priorité maximale.
    La priorité maximale est différente de la priorité TIME_CRITICAL, qu'il ne faut utiliser qu'à bon escient. Le cas que je t'ai décris est un cas adéquat, toutefois.

    Citation Envoyé par Auteur Voir le message
    il ne m'est pas venu à l'esprit d'utiliser cette fonction
    Tant mieux ! Je précisais à cause de la ressemblance forte entre les deux API (seul le Waitable les différencie), et je voulais être bien certain que tu ne confondes pas les deux.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

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

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