2017-02-11 60 views
1

有人可以给出一个具体的例子来演示非线程安全吗? (以类似的方式,以一个运作版本矿下面如果可能的)Ruby请给出一个简单的非线程安全示例

我需要演示非线程安全操作,使得我可以断言上的失败,并且然后执行互斥锁,使得一个示例类我可以测试我的代码是线程安全的。

我已经尝试了以下但没有成功,因为线程似乎并行运行。假设红宝石+ =操作者不是线程,该测试总是通过时,它不应:

class TestLock 
    attr_reader :sequence 

    def initialize 
    @sequence = 0 
    end 

    def increment 
    @sequence += 1 
    end 
end 

#RSpec test 
it 'does not allow parallel calls to increment' do 
    test_lock = TestLock.new 
    threads = [] 
    list1 = [] 
    list2 = [] 
    start_time = Time.now + 2 

    threads << Thread.new do 
    loop do 
     if Time.now > start_time 
     5000.times { list1 << test_lock.increment } 
     break 
     end 
    end 
    end 

    threads << Thread.new do 
    loop do 
     if Time.now > start_time 
     5000.times { list2 << test_lock.increment } 
     break 
     end 
    end 
    end 

    threads.each(&:join) # wait for all threads to finish 
    expect(list1 & list2).to eq([]) 
end 
+0

线程是非确定性的。这就是他们如此丑陋的原因。你不能让他们确定性地失败。即使您的锁定不正确,他们有时也会工作,无论如何。你用你的代码完美地演示了它,它适用于YARV,在JRuby和Rubinius上失败。 –

回答

1

这里是一个,而不是找到此外,串联,或类似的东西的竞争条件的例子,使用一个阻挡文件写入。

总结部分:

  • file_write方法执行2秒钟的阻挡写入。
  • file_read读取文件并将其分配给全局变量以在其他地方引用。
  • NonThreadsafe#test连续调用这些方法,在他们自己的线程中,没有互斥体。在调用之间插入sleep 0.2,以确保在尝试读取数据时已经开始阻止文件写入。在第二个线程上调用join,所以我们确定它将读取值设置为全局变量。它从全局变量中返回读取值。
  • Threadsafe#test做同样的事情,但包装每个方法调用互斥体。

这就是:

module FileMethods 
    def file_write(text) 
    File.open("asd", "w") do |f| 
     f.write text 
     sleep 2 
    end 
    end 
    def file_read 
    $read_val = File.read "asd" 
    end 
end 

class NonThreadsafe 
    include FileMethods 
    def test 
    `rm asd` 
    `touch asd` 
    Thread.new { file_write("hello") } 
    sleep 0.2 
    Thread.new { file_read }.join 
    $read_val 
    end 
end 

class Threadsafe 
    include FileMethods 
    def test 
    `rm asd` 
    `touch asd` 
    semaphore = Mutex.new 
    Thread.new { semaphore.synchronize { file_write "hello" } } 
    sleep 0.2 
    Thread.new { semaphore.synchronize { file_read } }.join 
    $read_val 
    end 
end 

而且测试:

expect(NonThreadsafe.new.test).to be_empty 
expect(Threadsafe.new.test).to eq("hello") 

至于解释。非线程安全的原因显示文件的读取值为空,这是因为当读取发生时,阻塞写入操作仍在发生。但是,当您使用同步互斥锁时,写入操作将在读取之前完成。还要注意,线程安全示例中的.join需要比非线程安全值更长的时间 - 这是因为它正在写入线程中指定的全部持续时间内休眠。