刚开始尝试线程,我想知道:是否存在使用多个 Mutex 有意义的情况?
我知道 Mutex#synchronize 用于锁定值,防止竞争条件。我正在使用它有点像这样:
# class variable
@semaphore = Mutex.new
# in thread in method
self.class.semaphore.synchronize{ x += 1 }
这是处理锁定的好方法吗?
刚开始尝试线程,我想知道:是否存在使用多个 Mutex 有意义的情况?
我知道 Mutex#synchronize 用于锁定值,防止竞争条件。我正在使用它有点像这样:
# class variable
@semaphore = Mutex.new
# in thread in method
self.class.semaphore.synchronize{ x += 1 }
这是处理锁定的好方法吗?
这是一条经验法则:始终为每组变量使用一个互斥锁。例如,对一个数组使用一个互斥锁,并为其元素的计数器使用总是一起使用的。如果两个不同的对象(或对象组)可以在逻辑上的不同时间由两个不同的线程使用并且不会破坏您的程序,请给它们不同的互斥锁。
用一个互斥锁来处理这种情况:
$counter1 = 0
$counter2 = 0
$mutex = Mutex.new #Just one mutex
threads = []
threads << Thread.new do
$mutex.syncronize do
3.times do |i|
sleep(1) #some calculation
$counter1 += i
end
end
end
threads << Thread.new do
$mutex.syncronize do
3.times do |i|
sleep(1) #some calculation
$counter2 += i * 3
end
end
end
threads.each {|t| t.join}
以下是时间值:
real 0m6.019s
user 0m0.012s
sys 0m0.004s
(因为睡眠低用户和系统)
这是一个有两个互斥锁的版本:
$counter1 = 0
$counter2 = 0
$mutex1 = Mutex.new
$mutex2 = Mutex.new
threads = []
threads << Thread.new do
$mutex1.syncronize do
3.times do |i|
sleep(1) #some calculation
$counter1 += i
end
end
end
threads << Thread.new do
$mutex2.syncronize do
3.times do |i|
sleep(1) #some calculation
$counter2 += i * 3
end
end
end
threads.each {|t| t.join}
和时间值:
real 0m3.021s
user 0m0.020s
sys 0m0.004s
速度提高了 2 倍,因为我们移除了强制两个线程相互等待的锁定条件,有效地消除了第一种情况下线程化的任何好处。显然,每个变量一个互斥锁是效率的一大提高。
当然,如果你有两个对象A和B是有意义的,每个对象都可以独立使用。如果 thread1 想要独占访问A,而 thread2 想要独占访问B,则 thread1 和 thread2 不需要相互等待。所以A有一个信号量,B有一个不同的信号量。不过要小心!例如,当 thread1 具有A并等待获取B而 thread2 具有B并等待获取A时,您可能会出现死锁。
有很多材料涵盖共享资源、死锁等。