Mutex
is a class that implements a simple
semaphore lock for mutually exclusive access to some shared resource.
That is, only one thread may hold the lock at a given time. Other
threads may choose to wait in line for the lock to become available,
or may simply choose to get an immediate error indicating that the
lock is not available.
A mutex is often used when updates to shared data need to be atomic.
Say we need to update two variables as part of a transaction. We can
simulate this in a trivial program by incrementing some counters. The
updates are supposed to be atomic---the outside world should never see
the counters with different values. Without any kind of mutex control,
this just doesn't work.
count1 = count2 = 0
|
difference = 0
|
counter = Thread.new do
|
loop do
|
count1 += 1
|
count2 += 1
|
end
|
end
|
spy = Thread.new do
|
loop do
|
difference += (count1 - count2).abs
|
end
|
end
|
sleep 1
|
Thread.critical = 1
|
count1
|
� |
184846
|
count2
|
� |
184846
|
difference
|
� |
58126
|
This example shows that the ``spy'' thread woke up a large number of
times and found the values of
count1
and
count2
inconsistent.
Fortunately we can fix this using a mutex.
require 'thread'
mutex = Mutex.new
count1 = count2 = 0
difference = 0
counter = Thread.new do
loop do
mutex.synchronize do
count1 += 1
count2 += 1
end
end
end
spy = Thread.new do
loop do
mutex.synchronize do
difference += (count1 - count2).abs
end
end
end
|
sleep 1
|
mutex.lock
|
count1
|
� |
21192
|
count2
|
� |
21192
|
difference
|
� |
0
|
By placing all accesses to the shared data under control of a mutex,
we ensure consistency. Unfortunately, as you can see from the numbers,
we also suffer quite a performance penalty.