📖 Scenario: You are creating a simple Ruby program where multiple threads try to update a shared counter. Without control, the counter can get wrong values because threads interfere with each other.To fix this, you will use a Mutex to make sure only one thread changes the counter at a time.
🎯 Goal: Build a Ruby program that uses a Mutex to safely update a shared counter from multiple threads.
📋 What You'll Learn
Create a shared counter variable
Create a Mutex object
Use multiple threads to increment the counter
Use the Mutex to synchronize access to the counter
Print the final value of the counter
💡 Why This Matters
🌍 Real World
Mutexes are used in programs where many parts run at the same time and share data. They help avoid mistakes when data is changed by more than one part at once.
💼 Career
Understanding thread synchronization and mutexes is important for software developers working on multi-threaded applications, servers, and any program that needs safe data sharing.
Progress0 / 4 steps
1
Create a shared counter variable
Create a variable called counter and set it to 0.
Ruby
Hint
Use counter = 0 to start the count at zero.
2
Create a Mutex object
Create a variable called mutex and set it to a new Mutex object using Mutex.new.
Ruby
Hint
Use mutex = Mutex.new to create a new mutex.
3
Create threads and synchronize counter increment
Create an array called threads. Use a 5.times loop to create 5 threads. Inside each thread, use mutex.synchronize to safely increment counter by 1.
Ruby
Hint
Use threads = [] to hold threads. Use 5.times do to create threads. Inside each thread, wrap counter += 1 with mutex.synchronize do ... end. Use threads.each(&:join) to wait for all threads.
4
Print the final counter value
Write a puts statement to print the value of counter.
Ruby
Hint
Use puts counter to show the final count.
Practice
(1/5)
1. What is the main purpose of using a Mutex in Ruby threads?
easy
A. To create new threads automatically
B. To prevent multiple threads from accessing shared data at the same time
C. To speed up thread execution by running them in parallel
D. To stop threads from running
Solution
Step 1: Understand what shared data means in threads
Shared data is information that multiple threads can access or change.
Step 2: Identify the role of Mutex
Mutex ensures only one thread changes shared data at a time to avoid errors.
Final Answer:
To prevent multiple threads from accessing shared data at the same time -> Option B
Quick Check:
Mutex protects shared data = prevent simultaneous access [OK]
Hint: Mutex locks shared data to avoid conflicts between threads [OK]
Common Mistakes:
Thinking Mutex speeds up threads
Believing Mutex creates threads
Assuming Mutex stops threads completely
2. Which of the following is the correct way to use a Mutex to protect a critical section in Ruby?
easy
A. mutex.synchronize { critical_code }
B. mutex.lock; critical_code
C. mutex.run(critical_code)
D. mutex.start { critical_code }
Solution
Step 1: Recall Mutex usage in Ruby
Ruby's Mutex class provides a synchronize method to wrap critical code safely.
Step 2: Compare options
Only mutex.synchronize { critical_code } is the correct and safe syntax.
Final Answer:
mutex.synchronize { critical_code } -> Option A
Quick Check:
Use synchronize method to protect code [OK]
Hint: Use mutex.synchronize { } to wrap critical code [OK]
Common Mistakes:
Forgetting to unlock mutex after lock
Using non-existent methods like run or start
Not wrapping critical code in a block
3. What will be the output of this Ruby code?
require 'thread'
mutex = Mutex.new
counter = 0
threads = 3.times.map do
Thread.new do
2.times do
mutex.synchronize { counter += 1 }
end
end
end
threads.each(&:join)
puts counter
medium
A. 2
B. 3
C. 6
D. 0
Solution
Step 1: Count total increments
There are 3 threads, each increments counter 2 times, total 3*2=6 increments.
Step 2: Understand mutex effect
Mutex ensures increments happen safely without losing counts, so final counter is 6.
Final Answer:
6 -> Option C
Quick Check:
3 threads * 2 increments each = 6 [OK]
Hint: Multiply threads by increments inside synchronize block [OK]
Common Mistakes:
Ignoring mutex and expecting wrong count
Counting only one thread's increments
Confusing thread join effect
4. Identify the problem in this Ruby code using Mutex and how to fix it:
require 'thread'
mutex = Mutex.new
counter = 0
threads = 2.times.map do
Thread.new do
mutex.lock
counter += 1
end
end
threads.each(&:join)
puts counter
medium
A. Threads are not joined properly; fix by joining inside the thread block
B. Mutex is not needed here; remove mutex.lock
C. counter should be initialized inside the thread
D. Missing mutex.unlock causes deadlock; fix by adding mutex.unlock after increment
Solution
Step 1: Check mutex usage
Mutex is locked but never unlocked, causing threads to wait forever (deadlock).
Step 2: Fix by unlocking mutex
After increment, call mutex.unlock or better use mutex.synchronize to auto-handle locking/unlocking.
Final Answer:
Missing mutex.unlock causes deadlock; fix by adding mutex.unlock after increment -> Option D
Quick Check:
Always unlock mutex after lock to avoid deadlock [OK]
Hint: Always unlock mutex or use synchronize block [OK]
Common Mistakes:
Forgetting to unlock mutex
Removing mutex when needed
Initializing shared data inside threads incorrectly
5. You want to safely update a shared hash from multiple threads in Ruby. Which approach correctly uses Mutex to avoid race conditions?
shared_hash = {}
mutex = Mutex.new
threads = 5.times.map do |i|
Thread.new do
10.times do |j|
# What goes here?
end
end
end
threads.each(&:join)
puts shared_hash.size