【发布时间】:2018-08-13 19:20:17
【问题描述】:
假设我有一对(生产者、消费者)YARV 线程 (Tp,Tc) 共享一个 Array q - Tp 推送到 q,并从中弹出 Tc .如果 push 和 pop 的执行顺序不重要,代码是否可以在没有任何同步机制的情况下工作?
【问题讨论】:
假设我有一对(生产者、消费者)YARV 线程 (Tp,Tc) 共享一个 Array q - Tp 推送到 q,并从中弹出 Tc .如果 push 和 pop 的执行顺序不重要,代码是否可以在没有任何同步机制的情况下工作?
【问题讨论】:
由于其全局解释器锁 (GIL),大多数时间在 MRI/YARV 中访问数组是线程安全的(并且仅存在于那里),因此大多是偶然的。
您仍然必须确保每次只执行一个操作并避免读/写结构。在 Rubinius 或 JRuby 等其他 Ruby 实现中,数组显然不是线程安全的。
话虽如此,Ruby 为线程间通信提供了不同的原语,巧合的是,它是 MRI/VARV 中唯一明确线程安全的类:Queue。它支持以线程安全的方式推送和弹出对象。
以 Ruby 文档中的这个例子为例:
queue = Queue.new
producer = Thread.new do
5.times do |i|
sleep rand(i) # simulate expense
queue << i
puts "#{i} produced"
end
end
consumer = Thread.new do
5.times do |i|
value = queue.pop
sleep rand(i/2) # simulate expense
puts "consumed #{value}"
end
end
还有一个维护良好的项目concurrent-ruby,它为跨线程并发编程提供了许多强大的原语。
【讨论】:
array[0] = array[1] +42 这样的操作不是线程安全的,因为在读取和写入之间可能存在重叠线程。您还必须确保一次只能从单个线程访问存储在数组/队列中的对象(或使用互斥锁来强制执行此操作)。