A mutex protects shared state while multiple threads update it.

Mutex Counter

mutex_counter.rb
rounds = 
counter = 0
lock = Mutex.new

threads = 2.times.map do
  Thread.new do
    rounds.times do
      lock.synchronize do
        counter += 1
      end
    end
  end
end

threads.each(&:join)
expected = rounds * threads.length

puts "rounds=#{rounds}"
puts "counter=#{counter}"
puts "expected=#{expected}"
rounds = 
counter = 0
lock = Mutex.new

threads = 2.times.map do
  Thread.new do
    rounds.times do
      lock.synchronize do
        counter += 1
      end
    end
  end
end

threads.each(&:join)
expected = rounds * threads.length

puts "rounds=#{rounds}"
puts "counter=#{counter}"
puts "expected=#{expected}"
rounds = 
counter = 0
lock = Mutex.new

threads = 2.times.map do
  Thread.new do
    rounds.times do
      lock.synchronize do
        counter += 1
      end
    end
  end
end

threads.each(&:join)
expected = rounds * threads.length

puts "rounds=#{rounds}"
puts "counter=#{counter}"
puts "expected=#{expected}"
mutex `Mutex#synchronize` lets one thread at a time run the critical section that changes shared data.