Outils pour utilisateurs

Outils du site


allegro:threads

====== Différences ====== Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

allegro:threads [2012/03/16 23:49]
mrhide [Détails]
allegro:threads [2012/06/29 17:02] (Version actuelle)
mrhide [Threads]
Ligne 1: Ligne 1:
-===== Threads =====+===== Allegro — Threads =====
  
 Dans cet article nous allons voir comment utiliser l'​interface de threading d'​Allegro. Dans cet article nous allons voir comment utiliser l'​interface de threading d'​Allegro.
- 
-FIXME faire le walktrough 
  
 ==== Exemple basique ==== ==== Exemple basique ====
Ligne 17: Ligne 15:
 typedef struct s_data ​ typedef struct s_data ​
 { {
- ALLEGRO_MUTEX ​  ​*mutex;​ +   ALLEGRO_MUTEX ​  ​*mutex;​ 
- ALLEGRO_COND ​   *cond; +   ​ALLEGRO_DISPLAY *display; 
- ALLEGRO_DISPLAY *display; +   ​ALLEGRO_BITMAP ​ *caret;
- ALLEGRO_BITMAP ​ *caret;+
 } DATA; } DATA;
  
 void init_DATA(DATA *data, ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP ​ *caret) void init_DATA(DATA *data, ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP ​ *caret)
 { {
- data->​mutex ​  = al_create_mutex();​ +   data->​mutex ​  = al_create_mutex();​ 
- data->​cond ​   = al_create_cond();​ +   ​data->​display = display; 
- data->​display = display; +   ​data->​caret ​  = caret;
- data->​caret ​  = caret;+
 } }
  
 void dest_DATA(DATA *data) void dest_DATA(DATA *data)
 { {
- al_destroy_mutex(data->​mutex); +   al_destroy_mutex(data->​mutex);​
- al_destroy_cond(data->​cond);+
 } }
  
Ligne 48: Ligne 43:
 int main(int argc, char **argv) int main(int argc, char **argv)
 { {
-    ​ALLEGRO_DISPLAY ​    ​*display ​    = NULL; +   ALLEGRO_DISPLAY ​    ​*display ​    = NULL; 
-    ALLEGRO_EVENT_QUEUE *event_queue = NULL; +   ​ALLEGRO_EVENT_QUEUE *event_queue = NULL; 
-    ALLEGRO_BITMAP ​     *caret ​      = NULL; +   ​ALLEGRO_BITMAP ​     *caret ​      = NULL; 
-    ALLEGRO_THREAD ​     *thread ​     = NULL; +   ​ALLEGRO_THREAD ​     *thread ​     = NULL; 
-    DATA data;+   ​DATA data; 
 +    
 +   ​if(!al_init()) { 
 +      fprintf(stderr,​ "​failed to initialize allegro!\n"​);​ 
 +      return -1; 
 +   }
  
-    ​if(!al_init()) { +   ​al_set_new_display_flags(ALLEGRO_NOFRAME | ALLEGRO_WINDOWED);​ 
-        fprintf(stderr,​ "​failed to initialize allegro!\n"​);​ +   ​display = al_create_display(SCREEN_W,​ SCREEN_H);​ 
-        return -1; +   if(!display) { 
-    }+      fprintf(stderr,​ "​failed to create display!\n"​);​ 
 +      return -1; 
 +   ​}
  
-    al_set_new_display_flags(ALLEGRO_NOFRAME | ALLEGRO_WINDOWED);​ +   caret al_create_bitmap(CARET_WIDTHCARET_HEIGHT); 
-    display ​al_create_display(SCREEN_WSCREEN_H); +   ​if(!caret) { 
-    if(!display) { +      fprintf(stderr,​ "​failed to create ​bouncer bitmap!\n"​);​ 
-        fprintf(stderr,​ "​failed to create ​display!\n"​);​ +      ​al_destroy_display(display);​ 
-        return -1; +      ​return -1; 
-    }+   ​}
  
-    caret = al_create_bitmap(CARET_WIDTH,​ CARET_HEIGHT);​ +   al_set_target_bitmap(caret); 
-    if(!caret) ​{ +   al_clear_to_color(al_map_rgb(2550, 255)); 
-        ​fprintf(stderr"​failed to create bouncer bitmap!\n"​); +   al_set_target_bitmap(al_get_backbuffer(display)); 
-        ​al_destroy_display(display);​ +   event_queue = al_create_event_queue();
-         return -1; +
-    }+
  
-    al_set_target_bitmap(caret);​ +   ​if(!event_queue) { 
-    al_clear_to_color(al_map_rgb(255,​ 0, 255)); +       ​fprintf(stderr,​ "​failed to create event_queue!\n"​);​ 
-    al_set_target_bitmap(al_get_backbuffer(display));​ +       ​al_destroy_bitmap(caret);​ 
-    event_queue = al_create_event_queue();​ +       ​al_destroy_display(display);​ 
- +       ​return -1; 
-    ​if(!event_queue) { +   ​}
-        fprintf(stderr,​ "​failed to create event_queue!\n"​);​ +
-        al_destroy_bitmap(caret);​ +
-        al_destroy_display(display);​ +
-        return -1; +
-    }+
     ​     ​
-    ​al_register_event_source(event_queue,​ al_get_display_event_source(display));​ +   al_register_event_source(event_queue,​ al_get_display_event_source(display));​ 
-    al_clear_to_color(al_map_rgb(0,​0,​0));​ +   ​al_clear_to_color(al_map_rgb(0,​0,​0));​ 
-    al_flip_display();​+   ​al_flip_display();​
  
-    ​init_DATA(&​data,​ display, caret);+   init_DATA(&​data,​ display, caret);
  
-    ​thread = al_create_thread(progressBar,​ &​data);​ +   thread = al_create_thread(progressBar,​ &​data);​ 
-    al_start_thread(thread);​+   ​al_start_thread(thread);​
     ​     ​
-    ​al_rest(10.0);​ /* Loading some awesome datas !! */+   al_rest(10.0);​ /* Loading some awesome datas !! */
     ​     ​
-    ​//​al_set_thread_should_stop(thread);​ /* appelée implicitement par l'​instruction ci-dessous */ +   //​al_set_thread_should_stop(thread);​ /* appelée implicitement par l'​instruction ci-dessous */ 
-    al_join_thread(thread,​ NULL);+   ​al_join_thread(thread,​ NULL);
     ​     ​
-    ​al_destroy_thread(thread);​ +   al_destroy_thread(thread);​ 
-    dest_DATA(&​data);​+   ​dest_DATA(&​data);​
  
-    ​al_destroy_bitmap(caret);​ +   al_destroy_bitmap(caret);​ 
-    al_destroy_display(display);​ +   ​al_destroy_display(display);​ 
-    al_destroy_event_queue(event_queue);​+   ​al_destroy_event_queue(event_queue);​
  
-    ​return 0;+   return 0;
 } }
  
-static void *progressBar(ALLEGRO_THREAD *thr, void *arg) {+static void *progressBar(ALLEGRO_THREAD *thr, void *arg) 
 +{ 
 +   ​ALLEGRO_TIMER ​      ​*timer ​      = NULL; 
 +   ​ALLEGRO_EVENT_QUEUE *event_queue = NULL; 
 +   ​ALLEGRO_EVENT ​      ev;
  
- ALLEGRO_TIMER ​      ​*timer ​      = NULL; +   DATA *data  = (DATA*) arg; 
- ALLEGRO_EVENT_QUEUE *event_queue = NULL; +   ​float num   = 2.0; 
- ALLEGRO_EVENT ​      ev; +   ​float xpos  = PADDING;
-  +
- DATA *data  = (DATA*) arg; +
- float num   = 2.0; +
- float xpos  = PADDING+
-  +
- if (!data->​display || !data->​caret) { +
- fprintf(stderr,​ "args are NULL!\n"​);​ +
- return NULL; +
-+
-  +
- timer = al_create_timer(1.0 / FPS); +
- if(!timer) { +
- fprintf(stderr,​ "​failed to create timer!\n"​);​ +
- return NULL; +
-+
-  +
- event_queue = al_create_event_queue();​ +
- if(!event_queue) { +
- fprintf(stderr,​ "​failed to create event queue!\n"​);​ +
- return NULL; +
-+
- al_register_event_source(event_queue,​ al_get_timer_event_source(timer));​ +
- al_start_timer(timer);​ +
- al_set_target_bitmap(al_get_backbuffer(data->​display));​ /* new context */ +
-  +
- while(!al_get_thread_should_stop(thr)) +
-+
- al_wait_for_event(event_queue,​ &ev);+
  
- // if(ev.type == ALLEGRO_EVENT_TIMER) /* ne peut être autre chose */ +   if (!data->​display || !data->​caret) { 
-  +      fprintf(stderr,​ "args are NULL!\n"​);​ 
- al_draw_bitmap(data->​caret,​ xpos, SCREEN_H-PADDING-CARET_HEIGHT,​ 0); +      return NULL; 
-  +   } 
- xpos += num; + 
- if (xpos >= SCREEN_W-PADDING) +   timer = al_create_timer(1.0 / FPS); 
- break; +   ​if(!timer) { 
-  +      fprintf(stderr,​ "​failed to create timer!\n"​);​ 
- al_flip_display();​ +      return NULL; 
-+   } 
-  + 
- al_destroy_timer(timer);​ +   ​event_queue = al_create_event_queue();​ 
- al_destroy_event_queue(event_queue);​ +   ​if(!event_queue) { 
- return NULL;+      fprintf(stderr,​ "​failed to create event queue!\n"​);​ 
 +      return NULL; 
 +   } 
 +   ​al_register_event_source(event_queue,​ al_get_timer_event_source(timer));​ 
 +   ​al_start_timer(timer);​ 
 +   ​al_set_target_bitmap(al_get_backbuffer(data->​display));​ /* new context */ 
 + 
 +   ​while(!al_get_thread_should_stop(thr)) 
 +   { 
 +      al_wait_for_event(event_queue,​ &ev); 
 +      ​// if(ev.type == ALLEGRO_EVENT_TIMER) /* ne peut être autre chose */ 
 + 
 +      al_draw_bitmap(data->​caret,​ xpos, SCREEN_H-PADDING-CARET_HEIGHT,​ 0); 
 + 
 +      xpos += num; 
 +      if (xpos >= SCREEN_W-PADDING) 
 +         ​break; 
 + 
 +      al_flip_display();​ 
 +   ​
 + 
 +   ​al_destroy_timer(timer);​ 
 +   ​al_destroy_event_queue(event_queue);​ 
 +   ​return NULL;
 } }
 </​file>​ </​file>​
Ligne 162: Ligne 156:
 ==== Détails ==== ==== Détails ====
  
 +<code c>
 +typedef struct s_data ​
 +{
 +   ​ALLEGRO_MUTEX ​  ​*mutex;​
 +   ​ALLEGRO_DISPLAY *display;
 +   ​ALLEGRO_BITMAP ​ *caret;
 +} DATA;
 +
 +void init_DATA(DATA *data, ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP ​ *caret)
 +{
 +   ​data->​mutex ​  = al_create_mutex();​
 +   ​data->​display = display;
 +   ​data->​caret ​  = caret;
 +}
 +
 +void dest_DATA(DATA *data)
 +{
 +   ​al_destroy_mutex(data->​mutex);​
 +}
 +</​code>​
 +
 +On crée une structure qui contient les ressources partagées, elle doit contenir minimum le **mutex** qui permet de demander l'​accès exclusif aux données afin d'​éviter de les corrompre (si par exemple 2 threads veulent modifier la même variable au même moment, la valeur finale de la variable est inconnue).
 +
 +//On peut ajouter une **condition** de type **ALLEGRO_COND** qui permet à un thread d'en interrompre un autre et le de relancer grâce aux fonctions **al_wait_cond** et **al_broadcast_cond**,​ utile pour les threads concurrents.//​
 +
 +<code c>
 +   ​thread = al_create_thread(progressBar,​ &data);
 +   ​al_start_thread(thread);​
 +    ​
 +   ​al_rest(10.0);​ /* Loading some awesome datas !! */
 +</​code>​
 +
 +On crée notre thread avec **al_create_thread** qui prend en paramètres une fonction (qui sera appelée par le thread nouvellement crée) et un argument (qui sera transmis à la fonction).
 +
 +**al_start_thread** démarre notre thread, ensuite on peut faire tourner le code gros consommateur de temps (représenté par **al_rest**),​ on sait que l'​affichage est géré par la fonction **progressBar**.
 +
 +C'est une fonction très simple que reprend des notions des articles précédents. Sachez que dessiner la barre de progression avec un bitmap c'est pas très intelligent ! on dispose de fonctions de dessin via ce greffon : [[allegro:​addon_primitives|Primitive]].
 +
 +On remarquera seulement ceci :
 +
 +<code c>
 +   ​al_set_target_bitmap(al_get_backbuffer(data->​display));​ /* new context */
 +</​code>​
 +
 +En effet, chaque thread possède son propre context, c'est à dire tout ce qui est global dans allegro est limité à un thread, donc pour pouvoir dessiner sur le canvas démarré dans le thread principal, il faut le transmettre via notre structure et prévenir notre nouveau thread.\\
 +Si votre jeu termine sur un **ASSERT**, c'est certainement du à une variable du context qui est à **NULL**, donc faites attention !
 +
 +==== Amelioration ====
 +
 +On décide d'​améliorer notre barre de progression,​ on veut que le thread principal contrôle l'​avancement de la barre : on ajoute donc la variable **data.percent**,​ un entier compris entre 0 et 100 pour définir la taille de notre barre en fonction de l'​avancement dans notre thread principal.\\
 +On doit aussi ajouter une condition pour que le thread principal déclenche le dessin dès qu'il modifie la variable.
 +
 +On modifie alors notre fonction qui dépend plus du timer :
 +
 +<code c>
 +static void *progressBar(ALLEGRO_THREAD *thr, void *arg)
 +{
 +   DATA *data  = (DATA*) arg;
 +   float pbar_1pc = (SCREEN_W-2*PADDING)/​100.0;​
 +   int goon = 1;
 +
 +   ​al_set_target_bitmap(al_get_backbuffer(data->​display));​
 +
 +   ​while(!al_get_thread_should_stop(thr) && goon)
 +   {
 +      al_lock_mutex(data->​mutex);​
 +      al_wait_cond(data->​cond,​ data->​mutex);​
 +      al_draw_bitmap(data->​caret,​ data->​percent*pbar_1pc,​ SCREEN_H-PADDING-CARET_HEIGHT,​ 0);
 +      if (data->​percent == 100)
 +         goon = 0;
 +      al_unlock_mutex(data->​mutex);​
 +
 +      al_flip_display();​
 +   }
 +
 +   ​return NULL;
 +}
 +</​code>​
 +
 +La fonction restera bloquée sur **al_wait_cond** tant que le thread parent n'a pas appelé **al_broadcast_cond**.
 +
 +Pour terminer ce type de thread, un **join** ne suffit pas car il n'​enlève pas les **locks** dûs aux conditions. Vous devez utiliser à la place :
 +
 +<code C>
 +    al_set_thread_should_stop(thread);​
 +    al_lock_mutex(data.mutex);​
 +    al_broadcast_cond(data.cond);​
 +    al_unlock_mutex(data.mutex);​
 +</​code>​
  
 +Maintenant que vous savez utiliser les threads, vous savez pratiquement tout ce qu'il y a à savoir sur le core d'​allegro,​ dans la suite de ce tutoriel nous aborderons les différents greffons d'​Allegro.
  
-[[allegro:​input|Précédent]] << [[allegro:​start|Sommaire]] >> [[allegro:​addons|Suivant]]+[[allegro:​input|Précédent]] << [[allegro:​start#articles|Sommaire]] >> [[allegro:​addons|Suivant]]
allegro/threads.1331938199.txt.gz · Dernière modification: 2012/03/16 23:49 par mrhide