我有一些代码,Ruby类FootballSeries.find(123)
上的类方法,它执行API调用...由于担心线程安全,一次只有一个线程可以进入此方法。由于最近对API的一些更改,我也支持以下... FootballSeries.find('Premiership')
,第二种(见下面的实现)只是进行临时调用,看看是否可以找到ID,然后使用递归调用自身ID。
class FootballSeries
@find_mutes = Mutex.new
class << self
def find(series_name_or_id)
@find_mutex.synchronize do
if series_name_or_id.is_a?(String)
if doc = search_xml_document(series_name_or_id)
if doc.xpath('//SeriesName').try(:first).try(:content) == series_name_or_id
@find_mutex.unlock
series = find(doc.xpath('//seriesid').first.content.to_i)
@find_mutex.lock
return series
end
end
elsif series_name_or_id.is_a?(Integer)
if doc = xml_document(series_name_or_id)
Series.new(doc)
end
end
end
end
end
end
没有第9行和第11行,就会出现recursive mutex lock: deadlock
错误(这很有意义......因此我的问题是,我可以释放并重新锁定互斥锁。(我重新锁定,以便{{1}退出,我不会在解锁我不拥有的互斥锁时出错...但我没有测试是否需要这样做)
这是一个理智的实现,还是我会更好地让synchronize
调用两个单独的方法,每个方法都使用自己的互斥锁进行保护? (示例find()
和find_by_id
)
我现在的工作(或者至少看起来有效)。
最后,奖励积分 - 我如何测试这种安全方法?
答案 0 :(得分:0)
这对我来说不太好,因为@find_mutex.unlock
将允许其他方法同时进入。此外,我不认为使用递归通常是这种方法调度 - 实际上你有两个方法塞进一个。我肯定将这两个分开,如果你想能够用不同的参数类型调用一个方法,只需检查参数的类型并调用其中一个。如果您不需要公开find_by_id
和find_by_name
,则可以将其设为私有,并将mutex.synchronize
仅放在find
中。