handle_interrupt

Thread.handle_interrupt(hash) { ... } â result of the block
Class Public methods

Changes asynchronous interrupt timing.

interrupt means asynchronous event and corresponding procedure by #raise, #kill, signal trap (not supported yet) and main thread termination (if main thread terminates, then all other thread will be killed).

The given hash has pairs like ExceptionClass => :TimingSymbol. Where the ExceptionClass is the interrupt handled by the given block. The TimingSymbol can be one of the following symbols:

:immediate

Invoke interrupts immediately.

:on_blocking

Invoke interrupts while BlockingOperation.

:never

Never invoke all interrupts.

BlockingOperation means that the operation will block the calling thread, such as read and write. On CRuby implementation, BlockingOperation is any operation executed without GVL.

Masked asynchronous interrupts are delayed until they are enabled. This method is similar to sigprocmask(3).

NOTE

Asynchronous interrupts are difficult to use.

If you need to communicate between threads, please consider to use another way such as Queue.

Or use them with deep understanding about this method.

Usage

In this example, we can guard from #raise exceptions.

Using the :never TimingSymbol the RuntimeError exception will always be ignored in the first block of the main thread. In the second ::handle_interrupt block we can purposefully handle RuntimeError exceptions.

th = Thread.new do
  Thead.handle_interrupt(RuntimeError => :never) {
    begin
      # You can write resource allocation code safely.
      Thread.handle_interrupt(RuntimeError => :immediate) {
        # ...
      }
    ensure
      # You can write resource deallocation code safely.
    end
  }
end
Thread.pass
# ...
th.raise "stop"

While we are ignoring the RuntimeError exception, it's safe to write our resource allocation code. Then, the ensure block is where we can safely deallocate your resources.

Guarding from TimeoutError

In the next example, we will guard from the TimeoutError exception. This will help prevent from leaking resources when TimeoutError exceptions occur during normal ensure clause. For this example we use the help of the standard library Timeout, from lib/timeout.rb

require 'timeout'
Thread.handle_interrupt(TimeoutError => :never) {
  timeout(10){
    # TimeoutError doesn't occur here
    Thread.handle_interrupt(TimeoutError => :on_blocking) {
      # possible to be killed by TimeoutError
      # while blocking operation
    }
    # TimeoutError doesn't occur here
  }
}

In the first part of the timeout block, we can rely on TimeoutError being ignored. Then in the TimeoutError => :on_blocking block, any operation that will block the calling thread is susceptible to a TimeoutError exception being raised.

Stack control settings

It's possible to stack multiple levels of ::handle_interrupt blocks in order to control more than one ExceptionClass and TimingSymbol at a time.

Thread.handle_interrupt(FooError => :never) {
  Thread.handle_interrupt(BarError => :never) {
     # FooError and BarError are prohibited.
  }
}

Inheritance with ExceptionClass

All exceptions inherited from the ExceptionClass parameter will be considered.

Thread.handle_interrupt(Exception => :never) {
  # all exceptions inherited from Exception are prohibited.
}
doc_ruby_on_rails
2015-05-17 11:55:20
Comments
Leave a Comment

Please login to continue.