Problem 12 Building H2O
Overview
The Building H2O problem is a classic synchronization challenge in concurrent programming. The main challenge is to ensure that two hydrogen threads and one oxygen thread are properly synchronized so that they can form a water molecule, H2O, without violating the given constraints. This scenario highlights the difficulty of coordinating multiple threads to achieve a specific sequence or grouping, making sure that they interleave in a way that leads to the correct result. It mirrors real-world situations where resources (in this case, threads) must be combined in the right proportions to achieve the desired outcome.
Pseudocode
Initialize: semaphore oxygen = 0 semaphore hydrogen = 0 mutex lock Procedure releaseOxygen(): lock.acquire() # Acquire lock to ensure atomic operations oxygen += 1 # Increment oxygen count if oxygen >= 1 and hydrogen >= 2: # Check for available threads to form a water molecule oxygen -= 1 # Decrement oxygen count hydrogen -= 2 # Decrement hydrogen count by 2 barrier.passOxygen() # Allow oxygen thread to pass the barrier barrier.passHydrogen() # Allow two hydrogen threads to pass the barrier barrier.passHydrogen() lock.release() # Release lock Procedure releaseHydrogen(): lock.acquire() # Acquire lock to ensure atomic operations hydrogen += 1 # Increment hydrogen count if oxygen >= 1 and hydrogen >= 2: # Check for available threads to form a water molecule oxygen -= 1 # Decrement oxygen count hydrogen -= 2 # Decrement hydrogen count by 2 barrier.passOxygen() # Allow oxygen thread to pass the barrier barrier.passHydrogen() # Allow two hydrogen threads to pass the barrier barrier.passHydrogen() lock.release() # Release lock
Note:
- The pseudocode uses semaphores and a mutex to synchronize the threads.
- The
barrier.passOxygen()andbarrier.passHydrogen()methods are conceptual and represent the action of the respective threads passing through the barrier and forming the water molecule. - The actual implementation might require more specific functions or methods depending on the programming language or environment used.
Algorithm Walkthrough
Algorithm walkthrough or dry run for the given C++ program, demonstrating the synchronization of Hydrogen and Oxygen atoms to create water molecules (H2O).
Initial Setup:
H2O h2o: Instantiate an H2O object.hydrogenCount = 0: Initialize hydrogen atom counter.- Initialize mutex and condition variables.
Thread Creation:
t1: Hydrogen thread, callingreleaseHydrogen()10 times.t2: Hydrogen thread, callingreleaseHydrogen()10 times.t3: Oxygen thread, callingreleaseOxygen()10 times.
Dry Run Steps:
-
t1 calls
releaseHydrogen():- Locks the mutex.
hydrogenCountis 0, so it increments to 1.- Calls
generateHydrogen(), printing "Hydrogen (H) generated!". - Unlocks the mutex.
-
t2 calls
releaseHydrogen():- Locks the mutex.
hydrogenCountis 1, so it increments to 2.- Calls
generateHydrogen(), printing "Hydrogen (H) generated!". - Signals t3 because there are now 2 Hydrogen atoms.
- Unlocks the mutex.
-
t3 calls
releaseOxygen():- Locks the mutex.
- Finds 2 Hydrogen atoms available (from steps 1 and 2).
- Resets
hydrogenCountto 0. - Calls
generateOxygen(), printing "Oxygen (O) generated!". - Prints "H2O is created!".
- Broadcasts signal to Hydrogen condition variable (wakes up any waiting Hydrogen threads).
- Unlocks the mutex.
-
Steps 1 to 3 repeat until all threads finish their iterations.
Considerations
- The exact order of execution can vary since thread scheduling is done by the operating system and may depend on system load, CPU availability, and other factors.
- The above steps assume an ideal scenario where threads execute in a perfect alternating order. In a real-world scenario, you might see multiple Hydrogen atoms generated before an Oxygen atom, especially since we have two Hydrogen-generating threads and only one Oxygen-generating thread.
- The program ensures that "H2O is created!" is printed only when there are enough atoms to form a water molecule, maintaining the chemical accuracy of the process.
By the end of the execution, you would see "Hydrogen (H) generated!", "Oxygen (O) generated!", and "H2O is created!" printed 20, 10, and 10 times, respectively, representing the formation of 10 water molecules.

import java.util.concurrent.Semaphore;
public class Solution {
// Semaphore to control the release of Hydrogen atoms
private final Semaphore hSemaphore;
// Semaphore to control the release of Oxygen atoms
private final Semaphore oSemaphore;
// Counter to keep track of the number of Hydrogen atoms
private int hCount;
public Solution() {
// Initialize semaphores, 2 permits for Hydrogen and 0 permits for Oxygen
// 2 permits for Hydrogen because we need two Hydrogens per H2O molecule
// 0 permits for Oxygen because we need to wait for two Hydrogens before releasing Oxygen
hSemaphore = new Semaphore(2);
oSemaphore = new Semaphore(0);
// Initialize the Hydrogen counter
hCount = 0;
}
// Method to release a Hydrogen atom
public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
// Acquire a permit to release Hydrogen
hSemaphore.acquire();
synchronized (this) {
// Release Hydrogen atom
releaseHydrogen.run();
// Increment the Hydrogen counter
hCount++;
// Check if there are two Hydrogen atoms
if (hCount == 2) {
// If yes, release an Oxygen atom
oSemaphore.release();
}
}
// Release the permit for the next Hydrogen
hSemaphore.release();
}
// Method to release an Oxygen atom
public void oxygen(Runnable releaseOxygen) throws InterruptedException {
// Acquire a permit to release Oxygen
oSemaphore.acquire();
synchronized (this) {
// Release Oxygen atom
releaseOxygen.run();
// Print the creation of a water molecule
System.out.println("H2O is generated!");
// Reset the Hydrogen counter for the next water molecule
hCount = 0;
// Release permits for the next two Hydrogen atoms
hSemaphore.release(2);
}
}
public static void main(String[] args) {
Solution h2o = new Solution();
// Lambda expression to define the release of Hydrogen
Runnable releaseHydrogen = () -> System.out.print("H ");
// Lambda expression to define the release of Oxygen
Runnable releaseOxygen = () -> System.out.print("O ");
// Start threads to simulate the release of atoms
for (int i = 0; i < 5; i++) {
new Thread(() -> {
try {
h2o.hydrogen(releaseHydrogen);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
new Thread(() -> {
try {
h2o.hydrogen(releaseHydrogen);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
new Thread(() -> {
try {
h2o.oxygen(releaseOxygen);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
}
}
🤖 Don't fully get this? Learn it with Claude
Stuck on Problem 12 Building H2O? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Progressively stronger hints — you still solve it.
I'm working on the problem **Problem 12 Building H2O** (Concurrency). Give me a HINT LADDER: start with the tiniest nudge, then wait. Only reveal the next, stronger hint when I ask. Do NOT show the full solution unless I type 'show solution'. Keep me doing the thinking. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
See the technique, not just code.
Explain the optimal approach to **Problem 12 Building H2O** with a VISUAL walkthrough: trace it on a small concrete example using ASCII art / a step-by-step diagram, narrate what changes each step, then give time & space complexity with a one-line derivation. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Catch bugs, edge cases, sub-optimality.
I'll paste my solution to **Problem 12 Building H2O**. Review it for correctness, missed edge cases, and time/space complexity, then coach me toward the optimal — don't just rewrite it. Ask me to paste my code now. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Lock in recognition with look-alikes.
Give me 2 problems that use the SAME underlying pattern as **Problem 12 Building H2O**. For each, let me attempt first, then review my answer and name the trigger signal that reveals the pattern. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.