2011-03-12 26 views
1

我已經通過FFI爲共享庫函數(第三方函數)編寫了一個包裝。該共享庫嘗試與服務器建立連接。在服務器不可達的連接建立期間,第三方功能等待3分鐘。爲了避免在使用rails時調用,我試圖使用下面的超時,但不幸的是它沒有工作。超時,系統超時&終止符不能用於基於FFI的功能

  1. 本地超時
  2. 系統超時
  3. 終結者

注:當我使用終結者由它車削解散過程中創建的額外過程。

我使用紅寶石企業版1.8

回答

2

似乎通過FFI塊紅寶石的調度程序調用完全,不允許任何線程。這可能與Ruby的綠色線程有關。

下面的例子示出的Ruby併發的行爲使用FFI時:克服這個

require 'ffi' 

module Sleep 
    extend FFI::Library 

    ffi_lib FFI::Library::LIBC 

    attach_function :sleep, [:uint], :void 
end 

thread = Thread.start do 
    count = 1 
    while count <= 10 
    puts count 
    count += 1 
    sleep 0.5 
    end 
end 

puts "FFI sleep" 
Sleep.sleep 5 # Everything blocks, second thread is run after sleep 

puts "Ruby sleep" 
sleep 5 # Scheduling works, other thread runs simultaneously 

thread.join if thread.alive? 

的一種方式,是叉單獨的過程來進行FFI呼叫,並且對那個代替超時:

require 'ffi' 
require 'timeout' 

module Sleep 
    extend FFI::Library 

    ffi_lib FFI::Library::LIBC 

    attach_function :sleep, [:uint], :void 
end 

child_pid = Process.fork do 
    Signal.trap("INT") do 
    exit 
    end 

    Sleep.sleep 5 
    exit 
end 

begin 
    Timeout::timeout(2) do 
    Process.wait(child_pid) 
    end 
rescue Timeout::Error 
    Process.kill("INT", child_pid) 
end 

在派生的子過程中,所有我們有興趣做,被監聽INT信號關機輕輕如果達到超時,當然做FFI電話。

在父進程中,我們只需要超時子進程,並殺死它,除非它按時完成。

+0

是有一個FFI交替或有一個變通來克服這個問題。 –

+0

使用解決方法更新了我的答案。 – gnab

+0

解決方法奏效,但它創建了很多不存在的流程。在這段時間內,它使我的服務器不可用。 –

0

您可以標記將阻塞在C庫中的函數作爲「阻塞」函數,並且FFI將在調用這些函數時解鎖GIL。 (需要ffi-1.0.x)。

例如

require 'ffi' 
module Sleep 
    extend FFI::Library 

    ffi_lib FFI::Library::LIBC 

    # Tell FFI that this function may block 
    @blocking = true 
    attach_function :sleep, [:uint], :void 
end 

@blocking不黏膩 - 你需要每一個「attach_function」叫,你要標記爲阻塞之前設置它。

而且它不是100%肯定的解決方案。中斷在本地代碼中被阻塞的函數將適用於可中斷的函數(例如睡眠,讀取,寫入等),但不適用於某些本地代碼(例如cpu密集型計算,可能還有許多其他類型)。

被警告:在ruby 1.8.x上,阻止函數調用是真的是慢(與阻止1.9或JRuby上的調用相比)。

1

的位清潔器:

require 'ffi' 

module Sleep 
    extend FFI::Library 

    ffi_lib FFI::Library::LIBC 

    attach_function :sleep, [:uint], :void, :blocking => true 
end