sections, single, master y barreras
sections: tareas distintas en paralelo
Sección titulada «sections: tareas distintas en paralelo»Cada section la ejecuta un hilo, una sola vez; secciones distintas pueden ir en hilos distintos. Es paralelismo funcional (distintas tareas), a diferencia de for (mismo trabajo sobre datos distintos). Hay barrera implícita al final, salvo nowait.
#pragma omp parallel num_threads(4) shared(a, b, c, d) private(i, id){ // ¿se puede usar nowait? #pragma omp sections nowait { #pragma omp section { for (i = 0; i < N; i++) { c[i] = a[i] + b[i]; printf("seccion 1. Hilo: %i it: %i \n ", omp_get_thread_num(), i); } } #pragma omp section { for (i = 0; i < N; i++) { d[i] = a[i] * b[i]; printf("seccion 2. Hilo: %i it: %i \n ", omp_get_thread_num(), i); } } }}Con 4 hilos, solo 2 trabajan (hay 2 secciones); los otros 2 no tienen nada que hacer. Cada sección completa la hace un único hilo (en una corrida: la sección 1 fue del hilo 1, de it: 0 a it: 19).
single y master
Sección titulada «single y master»single | master | |
|---|---|---|
| ¿Quién lo ejecuta? | cualquier hilo (el primero que llega) | solo el hilo 0 |
| ¿Los demás esperan al final? | sí (barrera implícita), salvo nowait | no |
| ¿Acepta cláusulas? | private, firstprivate, copyprivate, nowait | ninguna |
| Uso típico | E/S, inicializar algo compartido | reportes de avance |
#pragma omp parallel{ #pragma omp single nowait { a = 10; id = omp_get_thread_num(); b[id] = a; cout << "constructor Single ejecutado por el hilo " << id << endl; }}Salida real (4 hilos): constructor Single ejecutado por el hilo 3 y luego solo b[3] = 10; el resto de b sigue en -1. En otra corrida puede ser otro hilo: no se sabe cuál entra a un single.
Barreras: explícita e implícitas
Sección titulada «Barreras: explícita e implícitas»#pragma omp barrier: cada hilo que llega espera a todos los del equipo. Además hay barreras implícitas (y con ellas un flush) al final de:
parallel(siempre, es el join),for,sections,single(salvonowait).
No hay barrera al final de master ni de critical.
Cómo leerlo: el tiempo avanza a la derecha. Los tres hilos hacen su parte del for; los que terminan antes esperan (rojo claro) en la barrera implícita del for. Luego un solo hilo (el 0 en este ejemplo, podría ser cualquiera) ejecuta el single y los otros esperan en su barrera. El master lo hace solo el hilo 0 y no tiene barrera: los hilos 1 y 2 siguen de largo.
¿Quién espera a quién? Barreras implícitas
Arma el cuerpo de un #pragma omp parallel y mira dónde se frenan los hilos. Rojo = esperando.
for: barrera implícita al final (quítala con nowait).single: un hilo trabaja; los demás esperan al final (salvo nowait).- El cierre de
parallelsiempre tiene barrera (es el join).
Ejemp01_master.c: single + reduction + master en un bucle
Sección titulada «Ejemp01_master.c: single + reduction + master en un bucle»#pragma omp parallel num_threads(4){ do { #pragma omp for for (i = 1; i < n-1; ++i) xold[i] = x[i]; // barrera al final #pragma omp single { toobig = 0; } // uno reinicia; barrera al final #pragma omp for private(y, error) reduction(+:toobig) for (i = 1; i < n-1; ++i) { y = x[i]; x[i] = average(xold[i-1], x[i], xold[i+1]); // suavizado (como el PD01) error = y - x[i]; if (error > tol || error < -tol) ++toobig; } // barrera: toobig ya sumado #pragma omp master ++c; // solo el hilo 0 cuenta vueltas } while (toobig > 0);}Salida real (n = 512, tol = 0.01): iteration 12385, toobig=0.
singlereiniciatoobiguna vez y su barrera garantiza que nadie empieza a sumar antes.reduction(+:toobig)cuenta en paralelo sin carrera.masterincrementacsin barrera: solo el hilo 0 lo hace.
Ejercicio
Sección titulada «Ejercicio»En Ejemp01_master.c, ¿qué pasaría si toobig = 0 se hiciera con master en vez de single?
Ver solución
master no tiene barrera: otros hilos podrían empezar el siguiente for con reduction(+:toobig) antes de que el hilo 0 ponga toobig = 0. La lámina de U4.2 sobre reduction muestra exactamente ese error: la inicialización tiene que quedar antes de la reducción, con una barrier después del master, usando single (que trae barrera) o inicializando antes de la región paralela.
Errores típicos
Sección titulada «Errores típicos»- Creer que
mastertiene barrera al final. No la tiene;singlesí (salvonowait). - Decir que
singlelo ejecuta el hilo 0. Lo ejecuta el primero que llega; el que siempre es el 0 esmaster. - Poner un
barrierdentro de unif (id == 0), unsingleo unmaster: no todos los hilos llegan y el programa se cuelga (o el comportamiento no está definido). - Esperar que con 2 hilos y 3
sectioncorran las 3 a la vez: un hilo hace dos, una detrás de otra.
Práctica extra
Sección titulada «Práctica extra»Tres section que tardan 2 s, 1 s y 1 s. ¿Cuánto tarda el bloque sections con 1, 2 y 3 hilos? ¿Cuál es el speedup máximo?
Ver solución
- 1 hilo: 2 + 1 + 1 = 4 s.
- 2 hilos: el mejor reparto es un hilo con la de 2 s y el otro con las dos de 1 s → 2 s.
- 3 hilos: una sección por hilo → 2 s (manda la más larga).
Smáx = 4/2 = 2, aunque haya 3 hilos: el tiempo nunca baja de la sección más larga. Es el mismo argumento del camino crítico de un DAG.
Autoevaluación
0/5 correctas · 0 respondidassingle lo ejecuta…single se usa…Fuente ·U4.1 Paralelismo compartido-OMP.pdf (láminas 18–22, 25) · U4.2 Paralelismo compartido-OMP.pdf (master, barrier) · U4.3 Paralelismo compartido-OMP.pdf (sections, single) · semana_9/Ejemp03_sections_omp.cpp · semana_9/Ejemp04_single_omp.cpp · semana_9/sesionb/Ejemp01_master.c