如何使此代码线程安全?

时间:2016-10-14 02:49:30

标签: ruby multithreading

在这个简单的练习中学习Ruby多线程的各个方面......我确定我错过了一些明显的东西,请提前感谢你...我已经在这里告诉我的代码了跨多个线程运行时会导致问题。为什么以及如何修复?谢谢!

MAX_MESSAGES = 100
messageCounter = 0

def process_message(msg)
  if( msg.valid?  && message_counter < MAX_MESSAGES )
    msg.file
    message_counter += 1
  end
end

1 个答案:

答案 0 :(得分:0)

在大多数编程语言中,message_counter += 1对于多线程会有问题,因为它会转换为message_counter = message_counter + 1。问题是,这必须做两件事:获取message_counter的值并递增它,然后将结果存储在message_counter

想象两个线程并行执行此操作:它们都获得值0,它们都将其递增为1,然后它们都存储值1.因此即使处理了两条消息,message_counter也是1。

但是在Ruby中,根据您使用的解释器,message_counter += 1可能会或可能不会受到GVL的保护,因此如果将此方法放在一堆线程中,您可能实际上看不到任何奇怪的行为。由于多个线程试图同时访问相同的Ruby对象,GVL确保VM不会进入无效状态。因此,在受GVL保护的解释器(包括官方解释器)中,您通常可以在某些线程中抛出任何旧的Ruby代码,一切都会正常工作。

,GVL会尝试保护虚拟机以外的资源。因此,如果您有多个线程都试图打印到一个日志文件,或使用一个数据库连接,或从一个套接字读取,所有地狱都可以打败。在这些情况下,您需要使用Mutex来保护共享资源免受并发访问。即使您认为GVL可能会保护您,使用互斥锁仍然是一个好主意;在最坏的情况下,锁定/解锁时会产生轻微的开销。