A Barrier is a synchronization primitive that blocks a group of threads until all of them reach a common synchronization point. Once all threads arrive, the barrier “opens” and releases all waiting threads simultaneously.
Cyclic Barriers: The implementation is cyclic, meaning after opening, the barrier resets its counter and can be reused for subsequent synchronization rounds.
Here’s the complete barrier implementation from the simulator:
source/js/core/barrier.js
// Barrera ciclica simple: todos deben llegar para abrir paso.export class Barrier { constructor(participants) { // Cantidad de hilos que deben sincronizarse en el checkpoint. this.participants = Math.max(1, Number(participants) || 1); // Cola FIFO de hilos bloqueados esperando apertura de barrera. this.waitingQueue = []; // Cantidad de llegadas en la ronda actual. this.arrived = 0; // Hilos con permiso concedido despues de abrir barrera. this.granted = new Set(); } // Un hilo llega a la barrera y espera si aun no esta completo el grupo. arrive(thread) { // Si el hilo ya fue liberado por una apertura previa, pasa directo. if (this.granted.has(thread)) { this.granted.delete(thread); return { passed: true, opened: false, released: [] }; } this.arrived += 1; // Si todavia no llegan todos, el hilo se bloquea. if (this.arrived < this.participants) { thread.state = "blocked"; thread.blockedBy = this; if (!this.waitingQueue.includes(thread)) this.waitingQueue.push(thread); return { passed: false, opened: false, released: [] }; } // Ultimo en llegar: abre barrera y despierta a todos los bloqueados. const released = []; while (this.waitingQueue.length > 0) { const waitingThread = this.waitingQueue.shift(); waitingThread.state = "ready"; waitingThread.blockedBy = null; this.granted.add(waitingThread); released.push(waitingThread); } // Reinicio contador para posibles rondas futuras de barrera. this.arrived = 0; return { passed: true, opened: true, released }; }}
// Reset counter when barrier opensthis.arrived = 0;
This allows multiple barrier synchronizations:
// Round 1thread.arrive(barrier); // All threads sync// ... do work ...// Round 2thread.arrive(barrier); // All threads sync again// ... do more work ...
Use case: Iterative parallel algorithms where threads repeatedly synchronize between iterations (e.g., parallel matrix multiplication, game simulation steps).
Wrong Participant Count: If you create a barrier for N threads but only N-1 threads call arrive(), all threads block forever:
const barrier = new Barrier(5);// Only 4 threads call arrive()// All 4 block forever!
Thread Failure: If a thread crashes before reaching the barrier, all other threads block forever. Real implementations often provide timeout mechanisms.
Broken Barrier: If a thread arrives twice before the barrier opens, the count becomes incorrect:
Barriers are essential in parallel algorithms with phases:
// Parallel matrix multiplicationfor (let iteration = 0; iteration < maxIterations; iteration++) { // Phase 1: Each thread computes its portion computePartialResult(); // Barrier: Wait for all threads to finish phase 1 barrier.arrive(); // Phase 2: Each thread uses results from all threads combineResults(); // Barrier: Wait for all threads to finish phase 2 barrier.arrive();}
Without barriers, threads might read partial results from other threads, causing incorrect computations.