2011-03-12 3 views
1

共有ライブラリ関数(サードパーティ関数)のFFIを使用してラッパーを作成しました。この共有ライブラリは、サーバーとの接続を確立しようとします。サーバが到達可能でない接続確立中に、サードパーティ機能が3分間待機します。レールを呼び出す際に、次のタイムアウトを使用しようとしたのを避けるため、残念ながら動作しませんでした。タイムアウト、FFIベースの関数でシステムタイムアウトとターミネータが機能しない

  1. ネイティブタイムアウト
  2. システムタイムアウト
  3. ターミネーター

注:私はターミネーターを使用する場合、それによって作成された追加のプロセスは、として現存しないプロセスを回しました。私はルビーエンタープライズバージョン1.8

答えて

2

を使用しています

はFFIブロックRubyのスケジューラを介した通話を完全には、任意のスレッドを許可していないようです。これはRubyの緑色スレッドに関連している可能性があります。これを克服する

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通話を行うために別のプロセスをフォークし、その代わりに、タイムアウトを有することである。

以下の例では、Rubyの並行性は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 
関連する問題