SEPC - TP Threads
De Ensiwiki.
Sommaire |
Quelques outils bien pratiques
gdb avec les threads
Un petit exemple de ce qu'on peut faire avec les commandes info threads et thread :
(gdb) info threads 11 Thread 0xb346abb0 (LWP 18734) 0x08049224 in mandelbrot_pixel (x_int=472, y_int=156) at mandel.c:222 10 Thread 0xb3c6bbb0 (LWP 18733) 0x08049204 in mandelbrot_pixel (x_int=433, y_int=139) at mandel.c:220 9 Thread 0xb446cbb0 (LWP 18732) 0xffffe424 in __kernel_vsyscall () 8 Thread 0xb4c6dbb0 (LWP 18731) 0x08049202 in mandelbrot_pixel (x_int=370, y_int=144) at mandel.c:220 7 Thread 0xb546ebb0 (LWP 18730) 0x08049247 in mandelbrot_pixel (x_int=333, y_int=200) at mandel.c:219 6 Thread 0xb5c6fbb0 (LWP 18729) 0x0804923d in mandelbrot_pixel (x_int=181, y_int=265) at mandel.c:219 5 Thread 0xb6470bb0 (LWP 18728) mandelbrot_pixel (x_int=288, y_int=223) at mandel.c:221 4 Thread 0xb6c71bb0 (LWP 18727) 0x08049224 in mandelbrot_pixel (x_int=217, y_int=269) at mandel.c:222 3 Thread 0xb7472bb0 (LWP 18726) 0x0804923f in mandelbrot_pixel (x_int=231, y_int=252) at mandel.c:219 2 Thread 0xb7c74bb0 (LWP 18725) 0x080491f8 in mandelbrot_pixel (x_int=272, y_int=267) at mandel.c:220 * 1 Thread 0xb7da26c0 (LWP 18716) 0xffffe424 in __kernel_vsyscall () (gdb) where #0 0xffffe424 in __kernel_vsyscall () #1 0xb7fd4378 in pthread_join () from /lib/tls/i686/cmov/libpthread.so.0 #2 0x0804975c in draw_screen_thread () at mandel.c:366 #3 0x08049bcb in main (argc=3, argv=0xbfff8494) at mandel.c:465 (gdb) thread 8 [Switching to thread 8 (Thread 0xb4c6dbb0 (LWP 18731))]#0 0x08049202 in mandelbrot_pixel (x_int=370, y_int=144) at mandel.c:220 warning: Source file is more recent than executable. (gdb) where #0 0x08049202 in mandelbrot_pixel (x_int=370, y_int=144) at mandel.c:220 #1 0x08049360 in draw_slice (slice_number=11) at mandel.c:254 #2 0x08049620 in draw_slice_thread_shop (arg=0x0) at mandel.c:317 #3 0xb7fd3240 in start_thread () from /lib/tls/i686/cmov/libpthread.so.0 #4 0xb7e7b49e in clone () from /lib/tls/i686/cmov/libc.so.6 (gdb)
Être robuste aux erreurs
Quand on lance trop de threads sur la machine, ça ne se passe pas toujours bien. Pour être un peu robuste aux erreurs et comprendre ce qu'il se passe, ne pas oublier de tester les valeurs de retour de pthread_create, et d'afficher les messages d'erreurs appropriés :
void * res;
int i;
int errno;
for (i = 0; i < number_of_threads; i++) {
errno = pthread_create(&tab_ptid[i], NULL, draw_slice_thread_shop, NULL);
if (errno != 0) {
printf("ERROR: pthread_create failed (%s)\n",
strerror(errno));
}
}
printf ("Now, waiting for threads to complete\n");
for(i=0; i<number_of_threads; i++) {
errno = pthread_join(tab_ptid[i],&res);
if (errno != 0) {
printf("ERROR: pthread_join failed (%s)\n",
strerror(errno));
}
}
(on pourrait ajouter un exit(1) derrière les printf, ou un traitement d'erreur propre pour ne pas faire de pthread_join sur un thread qui n'a jamais vraiment été créé)
volatile, or not volatile
Une idée répandue (tellement répandue qu'elle s'est glissée dans les slides :-/) est qu'il faut utiliser le mot clé "volatile" sur toutes les variables partagées quand on fait de la programmation parallèle. En fait, c'est un peu plus compliqué : pour faire court, volatile va ralentir le programme, sans forcément résoudre les problèmes. Pour les détails, lire les deux articles suivants, c'est très bien expliqué :

