http://ruby-doc.org/core-1.9.3/Mutex.html
Mutex implements a simple semaphore that can be used to coordinate access to shared data from multiple concurrent threads.
Example:
require 'thread'
semaphore = Mutex.new
a = Thread.new {
semaphore.synchronize {
# access shared resource
}
}
b = Thread.new {
semaphore.synchronize {
# access shared resource
}
}
self.lock
begin
yield
ensure
self.unlock rescue nil
end
end
Example without Mutax:
#!/usr/bin/rubyrequire'thread' 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 puts "count1 : #{count1}" puts "count2 : #{count2}" puts "difference : #{difference}"
This will produce the following result:
count1 :1583766 count2 :1583766 difference :637992
#!/usr/bin/rubyrequire'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.newdo loop do mutex.synchronize do difference +=(count1 - count2).abs end end end sleep 1 mutex.lock puts "count1 : #{count1}" puts "count2 : #{count2}" puts "difference : #{difference}"
This will produce the following result:
count1 :696591 count2 :696591 difference :0
Handling Deadlock:
When we start using Mutex objects for thread exclusion we must be careful to avoid deadlock. Deadlock is the condition that occurs when all threads are waiting to acquire a resource held by another thread. Because all threads are blocked, they cannot release the locks they hold. And because they cannot release the locks, no other thread can acquire those locks.
This is where condition variables come into picture. A condition variable is simply a semaphore that is associated with a resource and is used within the protection of a particular mutex. When you need a resource that's unavailable, you wait on a condition variable. That action releases the lock on the corresponding mutex. When some other thread signals that the resource is available, the original thread comes off the wait and simultaneously regains the lock on the critical region.
Example:
#!/usr/bin/rubyrequire'thread' mutex =Mutex.new cv =ConditionVariable.new a =Thread.new{ mutex.synchronize { puts "A: I have critical section, but will wait for cv" cv.wait(mutex) puts "A: I have critical section again! I rule!"}} puts "(Later, back at the ranch...)" b =Thread.new{ mutex.synchronize { puts "B: Now I am critical, but am done with cv" cv.signal puts "B: I am still critical, finishing up"}} a.join b.join
This will produce the following result:
A: I have critical section, but will wait for cv (Later, back at the ranch...) B:Now I am critical, but am donewith cv B: I am still critical, finishing up A: I have critical section again! I rule!