Jc/md/lp-01/06Threads1. jc/md/lp-01/06Threads2 Objectif du chapitre Génération dune application...

Post on 03-Apr-2015

109 views 0 download

Transcript of Jc/md/lp-01/06Threads1. jc/md/lp-01/06Threads2 Objectif du chapitre Génération dune application...

jc/md/lp-01/06 Threads 1

Threads

jc/md/lp-01/06 Threads 2

Objectif du chapitre

• Génération d’une application avec thread– Création d’un thread– Identification d’un thread– Suspension/Reprise d’un thread– Destruction d’un thread– Contrôle de l’exécution

• Exemples de threads

jc/md/lp-01/06 Threads 3

Point de départ

• Partir d’une 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/06 Threads 4

Création de l’application

jc/md/lp-01/06 Threads 5

Application THREAD1

jc/md/lp-01/06 Threads 6

Platform Settings

jc/md/lp-01/06 Threads 7

Création d’un 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/06 Threads 8

Création d’un 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 l’identificateur de thread, le ThreadId

jc/md/lp-01/06 Threads 9

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 threadDWORD ResumeThread( HANDLE hThread );La fonction décrémente le compteur de mise en sommeil et retourne la valeur du compteur.

jc/md/lp-01/06 Threads 10

Fin d’un thread• Pour terminer proprement un thread, le mieux

est d’utiliser 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);

• L’appelant devra ensuite fermer le handle

jc/md/lp-01/06 Threads 11

Application THREAD1

• L’application 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 qu’il se termine en renvoyant un code de sortie

différent, par exemple 12345678

• Enfin, CloseHandle ferme le handle

jc/md/lp-01/06 Threads 12

Génération de l’application

• Fonction main THREAD1.cpp– Ouverture du fichier– Insertion du code de main

• Fonction A_MAIN– Insertion d’un nouveau fichier THREAD1fonc.cpp

dans le projet– Ouverture du fichier– Insertion du code de la fonction

• Compilation des fichiers .cpp• Génération de l’exécutable .exe

jc/md/lp-01/06 Threads 13

Ouverture de THREAD1.cpp

Onglet FileView

jc/md/lp-01/06 Threads 14

THREAD1 main (1)

#include "stdafx.h "#define ATTENTE 1000void WINAPI A_MAIN(LPDWORD p); //déclaration fonctionint WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow){

HANDLE hFils;DWORD argument_pour_le_fils; //pour l’exempleDWORD thread_fils_Id=0;LPDWORD lpThreadFilsId=&thread_fils_Id;DWORD code_mis_par_le_fils;

jc/md/lp-01/06 Threads 15

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/06 Threads 16

THREAD1 main (3)

do //boucle d’attente 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/06 Threads 17

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 ouvertereturn 0;

}

jc/md/lp-01/06 Threads 18

Insertion d’un fichier dans le projet

jc/md/lp-01/06 Threads 19

Type et nom du fichier inséré

jc/md/lp-01/06 Threads 20

Ouverture du nouveau fichier

jc/md/lp-01/06 Threads 21

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 l’argumentprintf("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(12345678); //valeur arbitraire

}

jc/md/lp-01/06 Threads 22

Insertion d’un fichier existant

jc/md/lp-01/06 Threads 23

Chemin d’accès au fichier

jc/md/lp-01/06 Threads 24

Après insertion du code

jc/md/lp-01/06 Threads 25

Génération de THREAD1.exe

Build THREAD1.exe

jc/md/lp-01/06 Threads 26

Exécution de THREAD1

• Vérifier la connexion et télécharger l’image– Target→Configure Remote Connexion…– Target→Download/Initialize

• Choisir et exécuter THREAD1– Target→Run 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/06 Threads 27

Résultat de l’exécution

jc/md/lp-01/06 Threads 28

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/06 Threads 29

Application THREAD2 : Main

• Récupération du ThreadId• Création d’un 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/06 Threads 30

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/06 Threads 31

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/06 Threads 32

THREAD2 main (3)

printf("WinMain: début du thread primaire de THREAD2\n");

hFils=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)A_MAIN,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/06 Threads 33

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/06 Threads 34

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-handlethreadId=GetCurrentThreadId();printf("A_Main: threadId= %d hLocal= %d\n",threadId,hLocal);SuspendThread(hLocal);ExitThread(87654321);

}

jc/md/lp-01/06 Threads 35

Mettre THREAD2 dans le noyau

jc/md/lp-01/06 Threads 36

MAKE IMAGE

jc/md/lp-01/06 Threads 37

Démarrer->Exécuter

jc/md/lp-01/06 Threads 38

Parcourir

jc/md/lp-01/06 Threads 39

Sélectionner THREAD2

jc/md/lp-01/06 Threads 40

OK

jc/md/lp-01/06 Threads 41

Résultat de l’exécution

jc/md/lp-01/06 Threads 42

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

l’appel à la fonction _wtoi() qui convertit la chaîne UNICODE donnée sur la ligne d’attente en un entier

• Nous supposerons que le paramètre fourni sur la ligne de commande est saisi correctement, car le but est de montrer l’accès à la ligne de commande et non de tester les chaînes proposées, soit par exemple 1000 ou 12345

• On peut imprimer la valeur lue par un printf

jc/md/lp-01/06 Threads 43

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 d’exécution avec le nom du programme suivi de 12345

jc/md/lp-01/06 Threads 44

Résultat de l’exécution

jc/md/lp-01/06 Threads 45

Conclusion

• Nous appris à créer des threads et à organiser les communications élémentaires entre un thread père et un thread fils