2017-02-11 81 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需要比非線程安全值更長的時間 - 這是因爲它正在寫入線程中指定的全部持續時間內休眠。