Threads Linux et Windows

Proposé par Jerry Kan

le 10 December 2006 à 13h 28mn 10s

14722 visualisations



[Attention certaines parties de ce tuto ont été mis a jours : Code exemple thread, et Ajout des pthreads-win32 ]

salut,

suite a la discussion sur les threads windows / linux dans le topic routines/Ode-Irrlicht, je poste ici un mini tutoriel sur la facon de faire des threads portables (oupas)

je ne suis pas l'auteur des codes proposés


une methode interressante est d'utiliser les threads posix sous windows en ajoutant la dll Pthread disponible sous licence LGPL ici (merci a Xavier Leroy, Ben Elliston,  John Bossom et Ross Johnson) :

http://sourceware.org/pthreads-win32/

(a noter qu'il existe des bibliotheques qui proposent leur propres threads (ex: Boost), et que ceux ci sont parfois portables )


THREAD POSIX PORTABLES :

le code qui suit a été modifié le 4/01/2007 , il est compatible windows linux (testé sous Fedora core, et Windows XP) , moyennant l'utilisation des dll pthrads disponibles ici : ftp://sourceware.org/pub/pthreads-win32 … -08-19.exe

la procédure d'installation des dll windows est décrite ci apres

un zip regroupant l'exemple ci dessous et tous les fichiers requis est disponible ici :

Code:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

/*
    * C compiler: cc -lpthread pthread1.c
      or
    * C++ compiler: g++ -lpthread pthread1.c 

*/


void *print_message_function( void *ptr );

main()
{
     pthread_t thread1, thread2;
     char *message1 = "Thread 1";
     char *message2 = "Thread 2";
     int  iret1, iret2;

    /* Create independent threads each of which will execute function */

     iret1 = pthread_create( &thread1, NULL, print_message_function, (void*) message1);
     iret2 = pthread_create( &thread2, NULL, print_message_function, (void*) message2);

     /* Wait till threads are complete before main continues. Unless we  */
     /* wait we run the risk of executing an exit which will terminate   */
     /* the process and all threads before the threads have completed.   */

     pthread_join( thread1, NULL);
     pthread_join( thread2, NULL); 

     printf("Thread 1 returns: %d\n",iret1);
     printf("Thread 2 returns: %d\n",iret2);
     exit(0);
}

void *print_message_function( void *ptr )
{
  char *message;int i;  message = (char *) ptr;

  for(i=0;i<20000000;i++){
    if(i%1000000 == 0)
      printf("%s \n", message);
  }
  


}

Compilation sous Linux

la plupart des distribs comportent les threads posix, aucun install n'est requise, tapez simplement :

Code:

langage C
    cc -lpthread pthread1.c
langage C++
    g++ -lpthread pthread1.c

Compilation sous windows avec Dev C++
(c'est a peut pres pareil avec Code::Block a la différence pret qu'il faut aller dans "linker")

telechargez la derniere version de pthread-w32-v-v-v-release.exe a cette adresse ftp://sourceware.org/pub/pthreads-win32/ 

cliquez sur l'exe, c'est un auto extractable qui produit 3 dossiers : Pre-built,  pthread, et QueueUserAPCEx
seul Prebuild nous interresse,

allez dans Pre-built\include
prenez les 3 .h et copiez les dans DevCpp\include\

allez dans Pre-built\lib
prenez les 4 .a et .lib et copiez les dans DevCpp\lib

toujours dans Pre-built\lib
prenez les 4 .dll et copiez les dans Dev-Cpp/bin


Creez un projet


Allez dans Projet/option du projet/ choisissez l'onglet parametre

cliquez sur "ajouter fichier", trouvez les .lib et les .a et ajoutez les
(il s'agit de libpthreadGC1.a, libpthreadGCE1.a , pthreadVC1.lib, pthreadVSE1.lib )

si vous avez du mal a les retrouver dans DevCpp\lib, vous pouvez aussi copier les .lib et les .a dans le repertoire projet (ou ailleur) et les lier de la meme facon


compilez, et c'est pret !




[remarque]
si ca ne marche pas, il est tres possible que ce soit parce que votre repertoire DevCpp n'est pas définit dans le path du systeme, la solution la plus simple est de copier les dll dans windows\system32



exemples

Pour ceux que ca interresse, je met aussi un lien vers un mini projet de jeu (pacman) fonctionnel et compilable (linux) qui utilise des pthreads est dispo ici :

http://www710.univ-lyon1.fr/~jciehl/Pub … man.tar.gz
http://www710.univ-lyon1.fr/~jciehl/Pub … ostp8.html


un autre exemple :(merci a Xter):
http://www.cppfrance.com/codes/WIN32-LI … 19908.aspx



Je termine avec quelques généralités sur les threads qui interresseront peut etre ce qui n'en ont jamais utilisé :

Programmation Concurrente :

l'utilisation de threads suppose le plus souvent une coordination des threads (cas typique du producteur/consommateur ) ansi qu'un acces réglementé a certaine données, (on ne veux pas deux threads accedent en meme temps a une meme structure de donnée (par souci de cohérence, si la structure passe par un etat incohérent lors d'une modification)

les threads posix offrent des fonctionnalités (en plus du thread actif/pause/stop) pour coordonner l'execution des threads, comme par exemple des mutex qui controlent l'acces a des ressources ou des activations / desactivations multiples

Pourquoi il vaut mieux s'en passer ?

L'utilisation des threads est a éviter autant que possible si une version "linéaire" est facilement concevable, en effet la preuve d'un algorithme non linéraire est tres difficile a faire, le debuggage est beaucoup plus difficile, ce n'est pas parce que le programme comporte plusieurs objet qui font des opérations simultanée qu'il est interressant de faire des threads

Autre probleme posé par les threads, il est impossible de garantir que chaque threads recoit un temps d'execution CPU identique aux autres, (le contraire est meme probable), parce que le systeme gere l'ordonancement de chaque threads selon sa propre logique, laquelle varie fonction des disponibilités du systemes

L'utilisation des Thread est a réserver pour les applications qui nécéssitent une réactivité concurrente, dans un serveur, ou une application graphique, le programme doit répondre rapidement a une requette quelque soit sa tache courante
(quand Office sauvegarde votre texte pendant 30sec, vous voulez quand meme pouvoir continuer a le taper)


Comment s'en passer ?

Il vaut donc mieux éviter de creer un jeu ou chaque personnage est un thread, car on court le risque de voir certains personnage agir plus rapidement que d'autres
La meilleure solution pour garantir un temps constant est d'implementer une liste des personnages, de parcourir chaque élément en appelant une méthode que nous a pouvons appeler "agir()" qui effectue un micro mouvement du perso

si la méthode "agir" est suceptible s'execter plus ou moins vite selon le contexte (si le personnage fait du pathfinding par exemple, il peut trouver son chemin plus ou moins vite selon la complexité du terrain) la solution est de choisir le temps a attendre,  noter le temps courant avant et apres l'action, et d'attendre une certaine durée tampon pour qu'il y ait toujours le meme intervalle de temps entre deux appels de "agir"


voila, j'espere que j'ai pas raconté trop de bétises


#1 

12-12-2006 00:32:34

kedu
Modérateur
Date d'inscription: 23-09-2006
Messages: 155

Et bien interessant tout ça ^^ Effectivement les threads ne sont pas à mettre en place à la légère.

Pour faire le lien avec Irrlicht, avec Copland on s'est rendu compte que si l'on devait intégrer un moteur physique, ce dernier devrait être dans un thread du même type que celui que tu décris dans ton dernier paragraphe. (pour qu'il y ait une réelle unité de temps indépendemment de la puissance du pc sur lequel est exécuté l'appli)

Il ne faut effectivement pas hésiter à tester le même programme sur un panel de configurations afin de trouver la meilleure façon de gérer les "actions simultanées"...

Hors ligne


#2 

12-12-2006 20:30:46

Jerry Kan
Habitué
Date d'inscription: 21-11-2006
Messages: 265

ah effectivement, si les fonction mettent un certain temps a retourner, ca doit etre interressant d'utiliser cette méthode pour controler la vitesse des appels tout en utilisant des threads, j'y avais pas pensé

Hors ligne


#3 

17-12-2006 11:07:41

Jerry Kan
Habitué
Date d'inscription: 21-11-2006
Messages: 265

"kedu" :

Pour faire le lien avec Irrlicht, avec Copland on s'est rendu compte que si l'on devait intégrer un moteur physique, ce dernier devrait être dans un thread du même type que celui que tu décris dans ton dernier paragraphe. (pour qu'il y ait une réelle unité de temps indépendemment de la puissance du pc sur lequel est exécuté l'appli)


tu peux détailler ce que tu entends par la ?
j'ai essayé de voir comment ca pourrait s'organiser, et je n'arrive pas a me représenter ca de facon cohérente,
si j'ai bien compris, d'un coté on met le programme d'affichage irrlicht, (sans thread ou dans un thread ?)
tandis que le moteur physique est dans un thread qui se relance a intervalles régulier pour mettre a jour les évènements physiques ? (ca fonctionne avec sleep(temps restant) ou un timer est préférable ?)

dans ce cas on va faire plusieurs affichages de la meme scene immobile non ? (entre deux appels de la physique)
Ca n'est pas visible au final ?

En me relisant, je me dit que c'est mieux que la solution qui consite a faire bouger tout le monde avec la physique, puis  afficher, puis attendre le temps restant, puisque l'affichage sera plus fluide
Par contre, il faut que les mouvement des Mesh qui ne sont pas directement gérés par la physique le soient dans la boucle physique, plutot que celle d'affichage, non ?

Alors quelle est la bonne architecture ? wink

Dernière modification par Jerry Kan (17-12-2006 11:08:17)

Hors ligne


#4 

17-12-2006 12:30:03

izguit
Administrateur
Lieu: 127.0.0.1
Date d'inscription: 14-09-2006
Messages: 306
Site web

@ Jerry kan :
En prenant ta solution de faire un grand loop qui inclut le rendu et la physique, imaginons que tu testes ton code sur un via c3 à 500Mhz avec un sli de 8800GTX (oui bon ok c'est pas possible et le cpu briderait la cg smile mais c'est pour l'exemple) La physique pomperait à mort sur le cpu, on serait à 2fps alors que les cg pourraient rendre plus de 1000fps... (exemle reversible avec un core 2 quadro et un chipset graphique smile )
Si on prends la solution threads, le rendu serait fluide, la position des objets serait juste actualisée beaucoup moins souvent. Ca permet d'avoir la "même vitesse" sur des configs différentes, ce qui est d'autant plus important si il y a une partie réseau.
Pis bon, ça fait plus propre smile

Il y a surement d'autres avantages

Corrigez-moi si je dis des conneries smile


Athlon 64 3000+ // 1Go RAM // Geforce 6600GT 128Mo
Turion 64 X2 // 1Go RAM // ATI X1250

Hors ligne


#5 

17-12-2006 13:56:11

Jerry Kan
Habitué
Date d'inscription: 21-11-2006
Messages: 265

oui j'ai bien compris qu'on avait tout a gagner avec des threads qui fonctionne par pas de temps, je suis completement d'accord, ce que je vois pas, c'est comment faire précisément , qui dans quel threads, avec quelles priorités, avec timer/sleep, avec du code linéraire, des threads deamon, ou seulement des fonctions lancées comme des threads etc ..

Hors ligne


#6 

17-12-2006 14:05:55

Jerry Kan
Habitué
Date d'inscription: 21-11-2006
Messages: 265

en fait apres reflexion je le fairai tout simplement avec 2 threads en boucle:

un thread qui fait les graphiques en boucle autant qu'il veut
et un autre qui fait la physique et les Mesh en se lancant tous les X pas de temps

j'ai bon ?

Hors ligne


#7 

17-12-2006 19:25:36

kedu
Modérateur
Date d'inscription: 23-09-2006
Messages: 155

Oui je pense que lorsqu'on intègre une lib physique c'est très difficile de faire quelque chose de valable sans exécuter la physique dans un thread à part. Je te dirais bien de regarder ce que l'on a fait avec Copland dans la section tutoriaux mais bon c'est en C# et en c++ la gestion des threads pfiou c'est pas la même ^^

Hors ligne


#8 

04-01-2007 12:23:14

Jerry Kan
Habitué
Date d'inscription: 21-11-2006
Messages: 265

je viens de mettre a jour mon tutoriel, il explique maintenant comment faire des threads posix portables

j'ai uploadé un zip avec un exemple et tous les fichiers requis dans le module du site :

http://irrlichtfr.free.fr/Tutoriaux/thread-portable.zip

Hors ligne


#9 

04-01-2007 18:40:10

Copland
Modérateur
Lieu: ZarbiLand
Date d'inscription: 22-09-2006
Messages: 657
Site web

Yes merci beaucoup, cela va m'être d'une grande utilité.
je regarde ça dès que j'ai la tronche disposé ! Encore merci


Config : I5 2400, ATI HD6870 1Go DDR5, 4Go DDR3.
Single Boot : Windows Seven.

Hors ligne


Options Liens officiels Caractéristiques Statistiques Communauté
Corrections
irrlicht
irrklang
irredit
irrxml
xhtml 1.0
css 2.1
Propulsé par FluxBB
Traduit par FluxBB.fr
883 membres
1429 sujets
11121 messages
Dernier membre inscrit: Saidov17
50 invités en ligne
Aucun membre connecté
RSS Feed