Overview
The Barrier class implements a cyclic synchronization barrier. All participating threads must arrive at the barrier before any can proceed. When the last thread arrives, the barrier opens, releasing all waiting threads, and then resets for potential reuse.
Constructor
The number of threads that must arrive at the barrier before it opens. Minimum value is 1.const barrier = new Barrier(3); // Wait for 3 threads
Initial State:
participants: Math.max(1, participants)
waitingQueue: []
arrived: 0
granted: new Set()
Properties
The total number of threads required to open the barrier.
FIFO queue of threads currently blocked waiting for the barrier to open.
Count of threads that have arrived in the current round (reset to 0 after barrier opens).
Set of threads that have been granted permission to pass after the barrier opened.
Methods
arrive(thread)
Thread arrives at the barrier and waits for all others to arrive.
The thread arriving at the barrier.
Object containing:
passed (boolean): true if thread can proceed, false if blocked
opened (boolean): true if this arrival opened the barrier (last thread)
released (Array<Thread>): List of threads released when barrier opened (empty if not opener)
Behavior:
- Already granted: If thread was previously granted permission, consumes grant and passes through
- Not all arrived: Increments
arrived count, blocks thread, adds to queue
- Last arrives: Opens barrier, releases all waiting threads, resets counter, returns all released threads
Source: barrier.js:15
// Example: Thread arriving at barrier
const result = barrier.arrive(thread1);
if (result.passed) {
if (result.opened) {
console.log('Last thread - barrier opened!');
console.log(`Released ${result.released.length} threads`);
} else {
console.log('Thread passed (was previously waiting)');
}
} else {
console.log('Thread blocked at barrier');
}
Usage Example
import { Barrier } from './core/barrier.js';
// Three threads must synchronize
const checkpoint = new Barrier(3);
// Thread 1
function thread1Code() {
console.log('Thread 1: Starting work');
doWork();
const result = checkpoint.arrive(thread1);
if (!result.passed) {
console.log('Thread 1: Waiting at barrier');
return; // Blocked
}
console.log('Thread 1: Continuing after barrier');
}
// Thread 2
function thread2Code() {
console.log('Thread 2: Starting work');
doWork();
const result = checkpoint.arrive(thread2);
if (!result.passed) {
console.log('Thread 2: Waiting at barrier');
return; // Blocked
}
console.log('Thread 2: Continuing after barrier');
}
// Thread 3 (last to arrive)
function thread3Code() {
console.log('Thread 3: Starting work');
doWork();
const result = checkpoint.arrive(thread3);
// This one opens the barrier
console.log(`Thread 3: Opened barrier, released ${result.released.length} threads`);
console.log('Thread 3: Continuing after barrier');
}
Cyclic Behavior
The barrier is cyclic - it automatically resets after opening:
const barrier = new Barrier(2);
// Round 1
barrier.arrive(thread1); // arrived = 1, blocked
barrier.arrive(thread2); // arrived = 0 (reset!), barrier opens
// Round 2 - can be reused
barrier.arrive(thread1); // arrived = 1, blocked
barrier.arrive(thread2); // arrived = 0 (reset!), barrier opens
The counter resets to 0 when the last thread arrives:
// Source: barrier.js:42
this.arrived = 0; // Reset for next round
Opening Sequence
When the last thread arrives, the barrier:
- Releases all waiting threads from the queue
- Grants each thread permission to pass
- Changes their state from
"blocked" to "ready"
- Resets the arrived counter to 0
- Returns the list of released threads
// Last thread arrives
if (this.arrived === this.participants) {
const released = [];
// Release all waiting threads
while (this.waitingQueue.length > 0) {
const waitingThread = this.waitingQueue.shift();
waitingThread.state = "ready";
waitingThread.blockedBy = null;
this.granted.add(waitingThread);
released.push(waitingThread);
}
this.arrived = 0; // Reset
return { passed: true, opened: true, released };
}
Grant Mechanism
Threads that were waiting receive a “grant” when released:
// When barrier opens
this.granted.add(waitingThread);
// When thread runs arrive() again
if (this.granted.has(thread)) {
this.granted.delete(thread); // Consume grant
return { passed: true, opened: false, released: [] };
}
This ensures that when a waiting thread is scheduled to run again, it can immediately pass through without re-checking the barrier condition.
Synchronization Pattern
const barrier = new Barrier(4);
// Four threads doing parallel work
function parallelPhase1() {
// Each thread does independent work
processData();
}
function synchronizationPoint(thread) {
const result = barrier.arrive(thread);
if (!result.passed) {
// Thread blocked - will resume here when barrier opens
return false;
}
return true; // Can proceed to phase 2
}
function parallelPhase2() {
// All threads synchronized - continue with next phase
processMoreData();
}
Timeline Example
const barrier = new Barrier(3);
// Time 0: Thread A arrives
barrier.arrive(threadA);
// arrived = 1, threadA blocked, queue = [threadA]
// Time 1: Thread B arrives
barrier.arrive(threadB);
// arrived = 2, threadB blocked, queue = [threadA, threadB]
// Time 2: Thread C arrives (LAST!)
const result = barrier.arrive(threadC);
// result.opened = true
// result.released = [threadA, threadB]
// threadA.state = "ready"
// threadB.state = "ready"
// threadC.state = "running" (never blocked)
// arrived = 0 (reset)
// queue = [] (empty)
// Time 3: All three threads continue past barrier
Use Cases
Barriers are ideal for:
- Phased parallel algorithms: All threads must complete phase N before any starts phase N+1
- Data parallel processing: Wait until all workers finish processing their chunk
- Checkpoint synchronization: Ensure all threads reach a checkpoint before proceeding
- Iterative algorithms: Synchronize at the end of each iteration
// Example: Parallel matrix computation
const workers = 4;
const barrier = new Barrier(workers);
function workerThread(workerId) {
for (let iteration = 0; iteration < 10; iteration++) {
// Each worker processes its portion
processMatrixChunk(workerId);
// Wait for all workers to finish this iteration
const result = barrier.arrive(thread);
if (!result.passed) {
return; // Blocked - will resume at next iteration
}
}
}