xis
xis

Reputation: 24850

How to make Ruby capture the syntax error in threads

I am trying to code up a two-threads client using ruby, one thread reads the data from a socket and print it out, the other thread reads local data and send it to remote server. The problem I found is that it looks like Ruby cannot capture errors within a thread, here is an example:

#! /usr/bin/ruby

Thread.new {
  loop {
    $stdout.puts "hi"
    abc.puts ef
    sleep 1
  }
}


loop {
  sleep 1
}

Obviously, outside the thread if I type abc.puts ef the code will never run since Ruby will report "undefined variable abc". However if it is within a thread, there is no error report. My question is, how to let Ruby capture errors like this? Or at least, report something is wrong within a thread?

Upvotes: 5

Views: 2214

Answers (3)

raubarede
raubarede

Reputation: 433

For syntax error catching, rescue must use explict Exception class (without this, rescue catch only StandardError) :

Thread.new {  
begin
  abc.puts ef
rescue  Exception => e
  puts "error #{e}"
end
}

see Why can't `rescue` catch exception classes other than `StandardError` by default?

Upvotes: 3

falsetru
falsetru

Reputation: 369064

Use Thread::abort_on_exception=:

According to Thread - Exception Handling:

Any thread can raise an exception using the raise instance method, which operates similarly to Kernel#raise.

However, it's important to note that an exception that occurs in any thread except the main thread depends on abort_on_exception. This option is false by default, meaning that any unhandled exception will cause the thread to terminate silently when waited on by either join or value. You can change this default by either abort_on_exception= true or setting $DEBUG to true.

...

Thread::abort_on_exception = true
Thread.new {
  loop {
    $stdout.puts "hi"
    abc.puts ef
    sleep 1
  }
}


loop {
  sleep 1
}

=>

hi
t.rb:5:in `block (2 levels) in <main>': undefined local variable or method `abc' for main:Object (NameError)
        from t.rb:3:in `loop'
        from t.rb:3:in `block in <main>'

Upvotes: 6

xis
xis

Reputation: 24850

Ok, one possible solution is surround the thread lambda with begin rescue end block:

Thread.new {
begin
  abc.puts ef
rescue
  puts error
end
}

Upvotes: 0

Related Questions