jc/md/lp-01/06Threads1
jc/md/lp-01/06Threads2 Objectif du chapitre Génération dune application avec thread –Création dun thread –Identification dun thread –Suspension/Reprise dun thread –Destruction dun thread –Contrôle de lexécution Exemples de threads
jc/md/lp-01/06Threads3 Point de départ Partir dune plate-forme de base pour émulateur de type « Industrial Controller » Construire (Build) la plate-forme Créer une application THREAD1 de type « Simple Windows CE Application »
jc/md/lp-01/06Threads4 Création de lapplication
jc/md/lp-01/06Threads5 Application THREAD1
jc/md/lp-01/06Threads6 Platform Settings
jc/md/lp-01/06Threads7 Création dun thread (1) Fonction CreateThread HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId); Valeur de retour : handle créé ou NULL
jc/md/lp-01/06Threads8 Création dun thread (2) : arguments lpThreadAttributes : NULL sous CE, dwStackSize : taille de la pile du thread créé lpStartAddress : pointeur sur le début du thread lpParameter : pointe une variable pour le thread dwCreationFlags : 0 pour démarrer le thread lpThreadId : pointeur sur une variable qui reçoit lidentificateur de thread, le ThreadId
jc/md/lp-01/06Threads9 Suspend/Resume Thread Gestion du compteur associé au thread Thread éligible quand ce compteur est nul Pour suspendre un thread DWORD SuspendThread( HANDLE hThread ); La fonction incrémente le compteur de mise en sommeil et retourne la valeur du compteur. Pour redémarrer un thread DWORD ResumeThread( HANDLE hThread ); La fonction décrémente le compteur de mise en sommeil et retourne la valeur du compteur.
jc/md/lp-01/06Threads10 Fin dun thread Pour terminer proprement un thread, le mieux est dutiliser la fonction ExitThread VOID ExitThread(DWORD dwExitCode); Le code de sortie est récupérable par celui qui a créé le thread par la fonction : BOOL GetExitCodeThread( HANDLE hThread, LPDWORD lpExitCode); Lappelant devra ensuite fermer le handle
jc/md/lp-01/06Threads11 Application THREAD1 Lapplication va créer un thread qui sera suspendu par la fonction Sleep La durée de la suspension est fixée par le paramètre fourni par CreateThread On vérifiera –Que le thread est actif en testant le code de retour 259 en décimal –Puis quil se termine en renvoyant un code de sortie différent, par exemple Enfin, CloseHandle ferme le handle
jc/md/lp-01/06Threads12 Génération de lapplication Fonction main THREAD1.cpp –Ouverture du fichier –Insertion du code de main Fonction A_MAIN –Insertion dun nouveau fichier THREAD1fonc.cpp dans le projet –Ouverture du fichier –Insertion du code de la fonction Compilation des fichiers.cpp Génération de lexécutable.exe
jc/md/lp-01/06Threads13 Ouverture de THREAD1.cpp Onglet FileView
jc/md/lp-01/06Threads14 THREAD1 main (1) #include "stdafx.h " #define ATTENTE 1000 void WINAPI A_MAIN(LPDWORD p); //déclaration fonction int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { HANDLE hFils; DWORD argument_pour_le_fils; //pour lexemple DWORD thread_fils_Id=0; LPDWORD lpThreadFilsId=&thread_fils_Id; DWORD code_mis_par_le_fils;
jc/md/lp-01/06Threads15 THREAD1 main (2) printf("WinMain: début du thread primaire de THREAD1\n"); argument_pour_le_fils=ATTENTE //en ms //Création du thread fils hFils=CreateThread( NULL,0, (LPTHREAD_START_ROUTINE)A_MAIN, &argument_pour_le_fils,0,lpThreadFilsId);
jc/md/lp-01/06Threads16 THREAD1 main (3) do //boucle dattente de la fin du thread fils { GetExitCodeThread(hFils,&code_mis_par_le_fils); //code actualisé à chaque passage printf("WinMain: code de retour du thread fils: %d\n",code_mis_par_le_fils); Sleep(400); //on redonne la main au système } while(code_mis_par_le_fils == STILL_ACTIVE);
jc/md/lp-01/06Threads17 THREAD1 main (4) printf("WinMain: fin de la boucle d'attente\n"); printf("WinMain: code de retour du thread fils : %d\n",code_mis_par_le_fils); CloseHandle(hFils); printf("WinMain: fin du thread primaire (main de THREAD1)\n"); getchar(); //attente d'un caractère pour maintenir la fenêtre ouverte return 0; }
jc/md/lp-01/06Threads18 Insertion dun fichier dans le projet
jc/md/lp-01/06Threads19 Type et nom du fichier inséré
jc/md/lp-01/06Threads20 Ouverture du nouveau fichier
jc/md/lp-01/06Threads21 Insertion du code de A_MAIN // THREAD1fonc.cpp #include "stdafx.h" //indispensable avec l'option /Yu du compilateur void WINAPI A_MAIN(LPDWORD pAdresse_argument) { DWORD attente; //utilisée pour une meilleure clarté printf("A_MAIN: début du thread fils\n"); attente=*pAdresse_argument; //récupération de largument printf("A_MAIN: argument envoyé par WinMain= %d\n",attente); Sleep(attente); printf("A_MAIN: fin du thread fils après attente de %d ms.\n",attente); ExitThread( ); //valeur arbitraire }
jc/md/lp-01/06Threads22 Insertion dun fichier existant
jc/md/lp-01/06Threads23 Chemin daccès au fichier
jc/md/lp-01/06Threads24 Après insertion du code
jc/md/lp-01/06Threads25 Génération de THREAD1.exe Build THREAD1.exe
jc/md/lp-01/06Threads26 Exécution de THREAD1 Vérifier la connexion et télécharger limage –TargetConfigure Remote Connexion… –TargetDownload/Initialize Choisir et exécuter THREAD1 –TargetRun Program Dans la boîte choisir Run Program choisir THREAD1.exe ou renseigner la zone Execution command line –Cliquer le bouton Run
jc/md/lp-01/06Threads27 Résultat de lexécution
jc/md/lp-01/06Threads28 Application THREAD2 Accès aux identificateurs de threads et aux handles par GetCurrentThreadId et GetCurrentThread –ThreadId du thread courant –ThreadId du père –ThreadId du fils SuspendThread ResumeThread
jc/md/lp-01/06Threads29 Application THREAD2 : Main Récupération du ThreadId Création dun pseudo-handle personnel Création du thread fils Impression des valeurs Réveil du thread fils après attente Lectures des codes de retour du fils Fermeture du handle fils Retour au système
jc/md/lp-01/06Threads30 THREAD2 main (1) // THREAD2.cpp //Defines the entry point for the appli. #include "stdafx.h" //obligatoire avec l'option de compil. /Yu #define ATTENTE 1000 //durée de l'attente void WINAPI A_MAIN (LPDWORD pAdresse_argument); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
jc/md/lp-01/06Threads31 THREAD2 main (2) { HANDLE hFils; HANDLE hPere; DWORD threadId_pere=0; DWORD threadId_fils=0; LPDWORD lpThreadFilsId=&threadId_fils; DWORD code_mis_par_le_fils;
jc/md/lp-01/06Threads32 THREAD2 main (3) printf("WinMain: début du thread primaire de THREAD2\n"); hFils=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)A_M AIN,NULL,0,lpThreadFilsId); hPere=GetCurrentThread(); threadId_pere=GetCurrentThreadId(); printf("WinMain: handle_pere= %d handle_fils= %d\n",hPere,hFils); printf("WinMain: threadId_pere= %d threadId_fils= %d\n",threadId_pere,threadId_fils); Sleep(ATTENTE); ResumeThread(hFils);
jc/md/lp-01/06Threads33 THREAD2 main (4) GetExitCodeThread(hFils,&code_mis_par_le_fils); printf("WinMain: code de retour du thread fils : %d\n",code_mis_par_le_fils); Sleep(ATTENTE); GetExitCodeThread(hFils,&code_mis_par_le_fils); printf("WinMain: code de retour du thread fils : %d\n",code_mis_par_le_fils); CloseHandle(hFils); printf("WinMain: fin du thread primaire (main de THREAD2)\n"); getchar(); //attente d'un caractère pour… return (0); }
jc/md/lp-01/06Threads34 THREAD2 fonction #include "stdafx.h" //indispensable avec l'option /Yu… void WINAPI A_MAIN(LPDWORD pAdresse_argument) { DWORD threadId=0; HANDLE hLocal; hLocal=GetCurrentThread(); //crée un pseudo-handle threadId=GetCurrentThreadId(); printf("A_Main: threadId= %d hLocal= %d\n",threadId,hLocal); SuspendThread(hLocal); ExitThread( ); }
jc/md/lp-01/06Threads35 Mettre THREAD2 dans le noyau
jc/md/lp-01/06Threads36 MAKE IMAGE
jc/md/lp-01/06Threads37 Démarrer->Exécuter
jc/md/lp-01/06Threads38 Parcourir
jc/md/lp-01/06Threads39 Sélectionner THREAD2
jc/md/lp-01/06Threads40 OK
jc/md/lp-01/06Threads41 Résultat de lexécution
jc/md/lp-01/06Threads42 Application THREAD3 Dans une nouvelle application, THREAD3, nous allons remplacer dans TRHEAD2 le paramètre ATTENTE par une valeur lue sur la ligne de commande. Suppression du #define ATTENTE Remplacement des deux occurrences de ATTENTE par lappel à la fonction _wtoi() qui convertit la chaîne UNICODE donnée sur la ligne dattente en un entier Nous supposerons que le paramètre fourni sur la ligne de commande est saisi correctement, car le but est de montrer laccès à la ligne de commande et non de tester les chaînes proposées, soit par exemple 1000 ou On peut imprimer la valeur lue par un printf
jc/md/lp-01/06Threads43 THREAD3 main (1) Supprimer –#define ATTENTE 1000 Remplacer les deux occurrences de –Sleep(ATTENTE); par –Sleep(_wtoi(lpCmdLine); THREAD3fonc identique à THRED2fonc Générer la nouvelle image puis exécuter en renseignant la boîte dexécution avec le nom du programme suivi de 12345
jc/md/lp-01/06Threads44 Résultat de lexécution
jc/md/lp-01/06Threads45 Conclusion Nous appris à créer des threads et à organiser les communications élémentaires entre un thread père et un thread fils