刚开始尝试使用线程,我在想:是否有一种情况使用多个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
(低用户因为睡眠SYS)
这里的带有两个互斥体的版本:
个$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
这是在速度X2增加,因为我们删掉了强迫两个线程等待对方的锁状态,有效去除线程中的任何利益第一种情况。显然,每个变量的一个互斥量是效率的大幅增加。
当然,这是有意义的,如果你有两个对象,甲和乙,其中的每一个可以独立地使用。如果thread1想要独占访问A,并且thread2想独占访问B,则thread1和thread2不需要彼此等待。所以A有一个信号量和B有一个不同的信号量。不过要小心!你可以得到死锁时,比方说,线程1具有一个并等待收购乙而线程2具有乙并等待收购一个。
有很多材料可以覆盖共享资源,死锁等等。