je reposte mon header qui permet de gérer des thread sout linux et windows.
#ifndef MY_THREAD_H #define MY_THREAD_H //Ces macros servent à uniformiser certaines fonctionnalités entre Windows et Linux. #ifdef WIN32 //macro version Windows # include <windows.h> //definition des threads # define callback_t unsigned long __stdcall # define thread_t HANDLE* # define thread_create(thrd, fct, param) thrd = new HANDLE;\ *(thrd) = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(fct),(param),0,NULL) # define thread_delete(thrd) CloseHandle(*(thrd));\ delete (thrd); # define thread_wait_close(thrd) WaitForMultipleObjects(1, *thrd, TRUE, INFINITE) //definition des semaphores et mutex # define mutex_t CRITICAL_SECTION # define mutex_init(mutex) InitializeCriticalSection((mutex)) # define mutex_lock(mutex) EnterCriticalSection((mutex)) # define mutex_unlock(mutex) LeaveCriticalSection((mutex)) # define mutex_delete(mutex) DeleteCriticalSection((mutex)) # define semaphore_t HANDLE # define semaphore_init(sema, max, place) ((sema) = CreateSemaphore(NULL, (max), (place), NULL)) # define semaphore_lock(sema) WaitForSingleObject((sema), INFINITE) # define semaphore_unlock(sema) ReleaseSemaphore((sema), 1, NULL) # define semaphore_delete(sema) CloseHandle(sema) #else //macro version Linux //definition des threads # include <pthread.h> # define callback_t void * # define thread_t pthread_t* # define thread_create(thrd, fct, param) (thrd) = new pthread_t;\ pthread_create((thrd), NULL, (fct), (param)) # define thread_delete(thrd) delete (thrd); # define thread_wait_close(thrd) pthread_join(*thrd, NULL) //definition des semaphores et mutex # include <semaphore.h> # define mutex_t pthread_mutex_t * # define mutex_init(mutex) (mutex) = new pthread_mutex_t;\ pthread_mutex_init ((mutex), NULL) # define mutex_lock(mutex) pthread_mutex_lock((mutex)) # define mutex_unlock(mutex) pthread_mutex_unlock((mutex)) # define mutex_delete(mutex) pthread_mutex_destroy((mutex));\ delete ((mutex)) # define semaphore_t sem_t* # define semaphore_init(sema, max, place) (sema) = new sem_t;\ sem_init ((sema), (max), (place)) # define semaphore_lock(sema) sem_wait((sema)) # define semaphore_unlock(sema) sem_post((sema)) # define semaphore_delete(sema) sem_destroy((sema));\ delete ((sema)) #endif #endif
Pour commencer un thread est un outils capable de lancer des exécution parallèles de code dans un même programme.
________________ | | | Code Principal | |________________| | intruction... | ________________ | | | execution du thread -> | Code du thread | | |________________| | | | | intruction... intruction... | | | | |-----------------------| | Fin du prog
Comme le dit l'autre tuto les thread sont à éviter tant qu'une exécution séquentiel est possible.
Mais pour un moteur 3d je dirais qu'ils sont conseillés surtout si il y a un moteur physique.
Je m'explique vous avez remarqué que les processeurs récents on tous des dual-corps. Et bien chaque thread s'exécute sur un corps différent se qui permet un gain énorme en performance.
Bien sur les threads ne sont pas a utilisés à la légère a cause des ressources critiques. Vous avez bien plusieurs processeurs mais qu'une seul Mémoire RAM. Et si 2 threads tentent d'accéder à la même partie de la mémoire et bien il risque de ne pas avoir les résultats voulus. Et même de faire planter le programme.
Je ne vais pas vous faire un court sur les risques des ressources critiques et vous demande de me croire sur parole que ceci est très dangereux pour un programme fiable.
Pour éviter de rentrer a plusieurs dans une zone critique il existe des fonctions de mise en attente. Les mutexs et le semaphores. Vous me dites "Je peux le faire moi même avec une variable global booléenne" Mais je vous répond que non car imaginé que pendant que vous tester votre variable et que vous changer d'état la variable, le processeur permute de thread. Vous risquez de rentrer à deux dans la zone critique et la de planter ou créer des erreurs dans votre programme.
Voici un petit programme simple avec l'utilisation des mutexs.
#include <iostream> #include "mythread.h" //creation du mutex mutex_t mut; mutex_t io; void trace(int x) { //Vue que trace est appeler par un thread //et qu'elle utilise les entrers sorties //il faut utiliser un autre mutex //ATTENTION voici la zone critique seule un thread à le droit //d'utiliser l'ES mutex_lock(io); printf("x = %d\n", x); mutex_unlock(io); //Fin de zone critique //un thread en file d'attente peut rentrer return; }; callback_t maFonc(void* x) { //recastage de x int* intX = (int*) //ATTENTION voici la zone critique seule un thread à le droit // de modifier la veleur de X mutex_lock(mut); //multiplication de x par lui même *intX = *intX * *intX; mutex_unlock(mut); //Fin de zone critique //un thread en file d'attente peut rentrer trace(*intX); return NULL; }; int main() { //Création de x int x; //initialisation du mutex mutex_init(mut); mutex_init(io); //Creation des threads thread_t thrd[10]; int i; for(i = 0; i < 10; i++) thread_create(thrd[i], maFonc, &x); //attente de la fermeture des threads for(i = 0; i < 10; i++) thread_wait_close(thrd[i]); //destruction des threads et du mutex for(i = 0; i < 10; i++) thread_delete(thrd); mutex_delete(mutex); mutex_delete(io); printf("\n\nX Final = %d\n", x); return 0; };
Par contre il y a une règle de syntaxe qui ne va pas dans se programme. Il est important de s'imposer que seul les fonctions callback et celle qui créer le thread doivent utiliser des mutexs. deonc le code serait mieux ainsi:
#include <iostream> #include "mythread.h" //creation du mutex mutex_t mut; void trace(int x) { printf("x = %d\n", x); return; }; callback_t maFonc(void* x) { //recastage de x int* intX = (int*) //ATTENTION voici la zone critique seule un thread à le droit // de modifier la veleur de X mutex_lock(mut); //multiplication de x par lui même *intX = *intX * *intX; trace(*intX); mutex_unlock(mut); //Fin de zone critique //un thread en file d'attente peut rentrer return NULL; }; int main() { //Création de x int x; //initialisation du mutex mutex_init(mut); //Creation des threads thread_t thrd[10]; int i; for(i = 0; i < 10; i++) thread_create(thrd[i], maFonc, &x); //attente de la fermeture des threads for(i = 0; i < 10; i++) thread_wait_close(thrd[i]); //destruction des threads et du mutex for(i = 0; i < 10; i++) thread_delete(thrd); mutex_delete(mutex); printf("\n\nX Final = %d\n", x); return 0; };
Pour finir les semaphores.
Je ne vais pas poster de code car il fonctionne comme les mutexs. À la seul différence c'est que, dans le create_semaphore, 'max' représente le nombre maximum de thread qui on le droit de rentrer dans la zone critique.
Et place est le nombre au quels sont déjà rentrer dans le semaphore.
je mexplique:
create_semaphore(sema, 10, 2);
10 processus auront le droit de rentrer dans le semaphore mais comme place = 2 seulement 8 pourront après l'initialisation. Donc si on fait un ...
create_semaphore(sema, 10, 10);
Aucun thread ne pourra rentrer dans la zone critique tant que l'on n'a pas fait un semaphore_unlock.
Astuce: create_semaphore(sema, 1, 0); est donc un mutex
---------------------------------------------------------------------------------------
PS : Je ne dit pas que cet header est parfait et sans bug mais je l'utilise personnellement et je n'est jamais eu un seul bug dessus.
Voilà à vos questions
super bien détaillé ton tuto,
je pense que je vais me servir de ton header,
merci
Hors ligne
Je suis en train d'essayer ca depuis un moment ce matin,
en fait je n'arrive pas a faire marcher le tout (pas testé sous linux), je suis sous code::block (meme erreur sous dev) , j'avoue que je suis pas tres habitué a windows (beuurk ^^ ) donc je rate peut etre un truc tout simple
j'ai créé un le .h et le .cpp comme tu le décrit, je clique sur le truc pour compiler et la :
Project : Console application Compiler : GNU GCC Compiler (called directly) Directory : C:\Documents and Settings\laurent\Bureau\th2\ -------------------------------------------------------------------------------- Switching to target: default Compiling: main.cpp In file included from main.cpp:2: mythread.h:29: error: expected constructor, destructor, or type conversion before '=' token mythread.h:29: error: expected `,' or `;' before '=' token main.cpp: In function `long unsigned int maFonc(void*)': main.cpp:23: error: cannot convert `CRITICAL_SECTION' to `_CRITICAL_SECTION*' for argument `1' to `void EnterCriticalSection(_CRITICAL_SECTION*)' main.cpp:27: error: cannot convert `CRITICAL_SECTION' to `_CRITICAL_SECTION*' for argument `1' to `void LeaveCriticalSection(_CRITICAL_SECTION*)' main.cpp:32: warning: converting to non-pointer type `long unsigned int' from NULL main.cpp: In function `int main()': main.cpp:41: error: cannot convert `CRITICAL_SECTION' to `_CRITICAL_SECTION*' for argument `1' to `void InitializeCriticalSection(_CRITICAL_SECTION*)' main.cpp:51: error: invalid conversion from `void*' to `void* const*' main.cpp:51: error: initializing argument 2 of `DWORD WaitForMultipleObjects(DWORD, void* const*, BOOL, DWORD)' main.cpp:57: error: `mutex' undeclared (first use this function) main.cpp:57: error: (Each undeclared identifier is reported only once for each function it appears in.) main.cpp:62:3: warning: no newline at end of file Process terminated with status 1 (0 minutes, 1 seconds) 10 errors, 1 warnings
la premiere des erreurs corresponds a la ligne :
*(thrd) = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(fct),(param),0,NULL)
éventuellement tu aurait un zip d'un exemple comprenant les sources et le .cbp (ou le .dev) ?
Dernière modification par Jerry Kan (04-01-2007 10:57:16)
Hors ligne
Je n'ai pratiquement pas de notion en c++ donc ne m'en veut pas si je me plante mais pour ta ligne d'erreur :
*(thrd) = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(fct),(param),0,NULL)
Est-ce que CreateThread est une méthode quelconque de la classe ou le constructeur de la classe ?
Si c'est un constructeur, il faudrait mettre new après le =. (si new est la bonne syntaxe en c++)
Désolé par avance si je suis à côté de la plaque :-/
Hors ligne
a priori non, puisque c'est un exemple qui ne comprends pas de classe,
comme c'est une ligne de la grosse macro du .h, je suis un peu perdu,
mais je suis arrivé a faire autrement en utilisant la librairie pthread.dll, et avec laquelle on peut porter les threads linux sans changement de code, je suis en train de mettre a jour mon tuto (l'autre tuto) pour expliquer comment faire
Hors ligne
Ah oui intéressant ça ! Si ça peut éviter de s'arracher les cheveux à faire des conversions (très passionnantes) de code...
Hors ligne
Je ne vois pas trop. je ne peut pas te faire un exemple pour windows car je ne l'est plus. Mais ces macro son utilisé en simplifier dans mk_socket (disponible sur l'upload). Et sa fonctionne sous win et linux. Enfin bon si tu trouve la source bug. envoie ta version corriger du header.
Hors ligne
je pense qu'une partie du problème viens du formatage fait par un copier coller
les lignes du type :
# define semaphore_delete(sema) sem_destroy((sema));\ delete ((sema));
doivent etre remplacée par
# define semaphore_delete(sema) sem_destroy((sema)); delete ((sema));
parce que pour une raison obscure, lors du copier coller, le caractere "\" a perdu son "pouvoir" a faire poursuivre sur la meme ligne
quand j'arrive a refaire marcher le tout je fait un zip et je l'upload
Dernière modification par Jerry Kan (05-01-2007 10:39:30)
Hors ligne
voila j'ai terminé le debug, ca fonctionne (testé windows et linux),
j'ai uploadé le zip avec le .h et les deux exemples ici
attention, j'ai modifié plusieurs choses dans le .h et .cpp donc ca marche un peu différemment qu'a l'origine, notamment coté utilisation des pointeurs,
Dernière modification par Jerry Kan (05-01-2007 13:14:58)
Hors ligne
Merci beaucoup pour le zip, je charge ça car je vais en avoir besoin...pas dans l'immédiat mais c'est prévu à mon programme donc un grand merci pour votre aide .
Hors ligne
Waow !! Que du bonheur vraiment merci, je viens de l'utiliser sous Windows pour gérer ma physique et ça a l'air de bien fonctionner !
Encore merci à vous pour se code et ses explications .
Hors ligne
Pages: 1