2009-08-25 39 views
2

我們如何鎖定多個ruby進程共享的IO?如何鎖定在紅寶石中分叉的IO

考慮這個腳本:

#!/usr/bin/ruby -w 
# vim: ts=2 sw=2 et 
if ARGV.length != 2 
    $stderr.puts "Usage: test-io-fork.rb num_child num_iteration" 
    exit 1 
end 
CHILD = ARGV[0].to_i 
ITERATION = ARGV[1].to_i 

def now 
    t = Time.now 
    "#{t.strftime('%H:%M:%S')}.#{t.usec}" 
end 

MAP = %w(nol satu dua tiga empat lima enam tujuh delapan sembilan) 

IO.popen('-', 'w') {|pipe| 
    unless pipe 
    # Logger child 
    File.open('test-io-fork.log', 'w') {|log| 
     log.puts "#{now} Program start" 
     $stdin.each {|line| 
     log.puts "#{now} #{line}" 
     } 
     log.puts "#{now} Program end" 
    } 
    exit! 
    end 
    pipe.sync = true 
    pipe.puts "Before fork" 
    CHILD.times {|c| 
    fork { 
     pid = Process.pid 
     srand 
     ITERATION.times {|i| 
     n = rand(9) 
     sleep(n/100000.0) 
     pipe.puts "##{c}:#{i} #{MAP[n]} => #{n}, #{n} => #{MAP[n]} ##{c}:#{i}" 
     } 
    } 
    } 

} 

,並嘗試這樣的:

./test-io-fork.rb 200 50 

像預期的那樣,測試-IO-fork.log文件將包含IO競爭狀態的跡象。

我想要實現的是爲自定義GPS協議創建一個TCP服務器,將GPS點保存到數據庫。由於該服務器將處理1000個併發客戶端,因此我想將數據庫連接限制爲只有一個子項,而不是同時打開1000個數據庫連接。該服務器將在Linux上運行。

回答

2

UPDATE

這可能是不好的形式答案被接受後更新,但原來是有點誤導。紅寶石是否獨立調用自動追加的換行符write(2)取決於輸出IO對象的緩衝狀態。

$stdout(當連接到一個tty)通常爲行緩衝,所以puts()的效果 - 給定的合理大小的串 - 與隱式添加新行是write(2)單個呼叫。但是,與OP一樣,IO.pipe$stderr並非如此。

原來的答案

更改您的首席pipe.puts()參數作爲一個換行符終止字符串:

pipe.puts "##{c} ... #{i}\n" # <-- note the newline 

爲什麼?您設置了pipe.sync希望管道寫入將是原子型和非交叉型,因爲它們(大概)小於PIPE_BUF字節。但它不起作用,因爲ruby的管道puts()執行發出一個單獨的調用來寫(2)以附加尾隨換行符,這就是爲什麼您的寫入有時會在您希望換行的地方進行交叉存取。

下面是腳本的一個叉下面strace的一個佐證摘錄:

$ strace -s 2048 -fe trace=write ./so-1326067.rb 
.... 
4574 write(4, "#0:12 tiga => 3, 3 => tiga #0:12", 32) = 32 
4574 write(4, "\n", 1) 
.... 

但將在自己的換行解決問題,確保您的整個記錄​​在一個系統調用傳輸:

.... 
5190 write(4, "#194:41 tujuh => 7, 7 => tujuh #194:41\n", 39 <unfinished ...> 
5179 write(4, "#183:38 enam => 6, 6 => enam #183:38\n", 37 <unfinished ...> 
.... 

如果由於某種原因無法爲您工作,您必須協調進程間互斥(如File.flock())。