Python Process Barrier

Python: Coordinating Processes with Barriers

When working with multiple processes in Python, it’s sometimes important to make sure they all reach a certain point before moving on. This is where multiprocessing.Barrier comes in. A barrier allows you to pause several processes at the same spot until all of them have arrived. Only when everyone is ready do they all proceed together.

Imagine a group of runners lining up at the start of a race. No one starts running until everyone is in position. That’s exactly what a barrier does in code.

In this article, you’ll learn how to use Barrier from the multiprocessing module to coordinate your processes. We’ll walk through creating a barrier, using it inside processes, and synchronizing steps in fun, easy-to-follow examples.

Setting Up: Imports and Creating a Barrier

To begin using a Barrier, you first need to import the right modules. We’ll use Process and Barrier from the multiprocessing module. We’ll also import time and random to simulate different delays in each process.

A Barrier is created with the number of parties (processes) that must call barrier.wait() before they can all continue. If the required number hasn’t been reached, the processes will pause and wait at the barrier.

Here’s a simple example that sets up a barrier for a space mission. We simulate three different systems—navigation, communication, and propulsion. Each one must say “Ready” before the launch can proceed.

from multiprocessing import Process, Barrier
import time
import random

# Create a barrier that waits for 3 processes
barrier = Barrier(3)

This sets up the coordination point. In the next section, we’ll create the processes and show how each one waits at the barrier.

Using Barrier in a Process Function

To coordinate multiple processes, each process calls barrier.wait() at the point where it should pause and wait for the others. This makes sure no process moves forward until all have reached the same checkpoint.

In this example, each system simulates a check that takes a random amount of time. After finishing its check, the process prints that it’s “Ready” and then calls barrier.wait() to pause. Only when all processes have reached the barrier do they all continue, printing that they are proceeding after launch clearance.

def system_check(name, barrier):

    time.sleep(random.uniform(0.5, 2))  # Simulate system check time

    print(f"{name} ready.")

    barrier.wait()  # Wait for other processes here

    print(f"{name} proceeding after launch clearance.")

This pattern is how you synchronize multiple processes at a specific point in your program. Next, we’ll see how to launch these processes together.

Launching and Joining Processes

To use the Barrier effectively, you create multiple processes that share the same Barrier instance. The number you pass to the Barrier must exactly match the number of processes that will call wait(). This ensures all processes pause and then proceed together.

Below is a complete program simulating three systems preparing for a rocket launch. Each system runs the system_check function, waits at the barrier, then continues once all are ready.

from multiprocessing import Process, Barrier
import time
import random

def system_check(name, barrier):

    time.sleep(random.uniform(0.5, 2))  # Simulate system check

    print(f"{name} ready.")

    barrier.wait()  # Wait for other systems

    print(f"{name} proceeding after launch clearance.")


if __name__ == "__main__":

    barrier = Barrier(3)  # Number of systems/processes

    systems = ['Navigation', 'Communication', 'Propulsion']
    processes = []

    for system in systems:

        p = Process(target=system_check, args=(system, barrier))
        p.start()

        processes.append(p)

    for p in processes:
        p.join()

When you run this, each system reports readiness at different times but all wait until everyone is ready before proceeding together. This shows how Barrier coordinates processes smoothly.

Barrier with Time Delays

The Barrier makes sure that even if processes reach the synchronization point at different times, none will move forward until all have arrived. This is especially useful when tasks take variable time to complete.

In the example below, each system simulates a prep task by sleeping for a random time. Despite the staggered finishes, the barrier.wait() call holds each process until everyone is ready.

from multiprocessing import Process, Barrier
import time
import random

def system_check(name, barrier):

    prep_time = random.uniform(0.5, 3)
    time.sleep(prep_time)

    print(f"{name} ready after {prep_time:.2f} seconds.")

    barrier.wait()

    print(f"{name} proceeding after launch clearance.")


if __name__ == "__main__":

    barrier = Barrier(3)

    systems = ['Navigation', 'Communication', 'Propulsion']
    processes = []

    for system in systems:
        p = Process(target=system_check, args=(system, barrier))
        p.start()
        processes.append(p)

    for p in processes:
        p.join()

Output will look something like:

Navigation ready after 1.76 seconds.
Propulsion ready after 1.78 seconds.
Communication ready after 2.33 seconds.
Navigation proceeding after launch clearance.
Propulsion proceeding after launch clearance.
Communication proceeding after launch clearance.

Notice how even though Navigation finishes first, it waits until Communication and Propulsion finish too. Only then do all processes print their “proceeding” message, showing the barrier’s synchronization in action.

Fun Example: Dungeon Adventure Synchronization

Let’s imagine three adventurers—a warrior, a mage, and a rogue—getting ready to enter a dungeon together. Each prepares at their own pace, but none can enter until all are ready. We use a Barrier to make sure they wait for each other at the dungeon gate before stepping inside.

from multiprocessing import Process, Barrier
import time
import random

def prepare_and_enter(name, barrier):

    prep_time = random.uniform(1, 4)
    print(f"{name} is preparing for the dungeon (will take {prep_time:.2f} seconds)...")

    time.sleep(prep_time)

    print(f"{name} is ready and waiting at the dungeon gate.")

    barrier.wait()

    print(f"{name} enters the dungeon!")


if __name__ == "__main__":

    barrier = Barrier(3)

    adventurers = ['Warrior', 'Mage', 'Rogue']
    processes = []

    for adventurer in adventurers:
        p = Process(target=prepare_and_enter, args=(adventurer, barrier))
        p.start()
        processes.append(p)

    for p in processes:
        p.join()

In this fun scenario, each adventurer takes a different time to prepare. Thanks to the barrier, they all meet at the gate before moving forward together. The output shows their preparation times, waiting, and entering in sync!

Using the action Parameter in Barrier

The Barrier object lets you specify an optional action parameter—a function that runs exactly once when all processes arrive at the barrier, just before they continue.

This is useful for triggering a special event or message when everyone is ready.

Here’s how you can use it in a space launch simulation. The action prints a launch message right when all systems reach the barrier:

from multiprocessing import Process, Barrier
import time
import random

def launch():
    print("🚀 All systems go! Launching now.")

def system_check(name, barrier):

    time.sleep(random.uniform(0.5, 2))
    print(f"{name} ready.")

    barrier.wait()

    print(f"{name} proceeding after launch clearance.")


if __name__ == "__main__":

    barrier = Barrier(3, action=launch)  # Launch action runs once all are ready

    systems = ['Navigation', 'Propulsion', 'Communication']
    processes = []

    for system in systems:
        p = Process(target=system_check, args=(system, barrier))
        p.start()
        processes.append(p)

    for p in processes:
        p.join()

When you run this, after all three systems print “ready,” the launch() function runs once, printing the launch message before all processes continue. This lets you coordinate a special event exactly when the barrier releases.

Reusing Barriers Across Stages

A Barrier can be used multiple times throughout your program to coordinate several stages of work. Once all processes pass the barrier, it resets automatically, ready to be used again.

For example, imagine a simple two-round game where players need to sync up twice: once when entering the game and again before calculating scores.

Each round uses barrier.wait() to make sure everyone is ready before moving on.

Here’s a complete example demonstrating this:

from multiprocessing import Process, Barrier
import time
import random

def player(name, barrier):

    # Round 1: Ready to enter the game
    time.sleep(random.uniform(0.5, 1.5))
    print(f"{name} ready to enter the game.")
    barrier.wait()
    print(f"{name} entered the game.")

    # Round 2: Ready to calculate scores
    time.sleep(random.uniform(0.5, 1.5))
    print(f"{name} ready to calculate scores.")
    barrier.wait()
    print(f"{name} finished score calculation.")


if __name__ == "__main__":

    player_count = 3
    barrier = Barrier(player_count)

    players = ['Warrior', 'Mage', 'Rogue']
    processes = []

    for p_name in players:
        p = Process(target=player, args=(p_name, barrier))
        p.start()
        processes.append(p)

    for p in processes:
        p.join()

In this example, the barrier is reused twice. First, all players wait at the barrier before entering the game together. Later, they wait again to calculate scores simultaneously. The barrier automatically resets after releasing the first time, enabling this repeated synchronization.

Conclusion

The multiprocessing.Barrier is a simple and effective way to synchronize multiple processes in Python. It makes sure that all processes wait for each other at specific points in the program before continuing. This coordination is especially useful when every process must reach the same checkpoint before any can proceed.

Whether you’re building games, running simulations, or managing multi-stage workflows, using a Barrier can help keep your processes in step with each other. Give it a try to keep your parallel tasks perfectly coordinated.

Scroll to Top