Class: CleanThread

Inherits:
Object
  • Object
show all
Defined in:
lib/clean_thread/version.rb,
lib/clean_thread.rb

Overview

reopen

Defined Under Namespace

Classes: ThreadFinish

Constant Summary collapse

VERSION =
"1.0.0"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args, &block) ⇒ CleanThread

Initialize a new CleanThread object.

If a block is given, that block will be executed in a new thread when the start method is called. If no block is given, the main method will be used.

The block is passed the CleanThread instance it belongs to, plus any arguments passed to the new method.



32
33
34
35
36
37
38
# File 'lib/clean_thread.rb', line 32

def initialize(*args, &block)
  @_cleanthread_mutex = Mutex.new
  @_cleanthread_stopping = false  # locked by _cleanthread_mutex
  @_cleanthread_thread = nil  # locked by _cleanthread_mutex.  Once set, it is not changed.
  @_cleanthread_proc = block
  @_cleanthread_args = args
end

Class Method Details

.check_finishingObject

If the current thread was invoked by CleanThread, invoke CleanThread#check_finishing.



11
12
13
14
15
# File 'lib/clean_thread.rb', line 11

def self.check_finishing
  ct = Thread.current[:clean_thread]
  return nil if ct.nil?
  ct.check_finishing
end

.finishing?Boolean

If the current thread was invoked by CleanThread, return the result of CleanThread#finishing?. Otherwise, return nil.

Returns:

  • (Boolean)


19
20
21
22
23
# File 'lib/clean_thread.rb', line 19

def self.finishing?
  ct = Thread.current[:clean_thread]
  return nil if ct.nil?
  return ct.finishing?
end

Instance Method Details

#alive?Boolean

Return true if the thread is alive.

Returns:

  • (Boolean)


98
99
100
# File 'lib/clean_thread.rb', line 98

def alive?
  @_cleanthread_thread && @_cleanthread_thread.alive?
end

#check_finishingObject

Exit the thread if the finish method has been called.

Functionally equivalent to:

raise ThreadFinish if finishing?

Raises:



116
117
118
119
# File 'lib/clean_thread.rb', line 116

def check_finishing
  raise ThreadFinish if finishing?
  return nil
end

#finish(options = {}) ⇒ Object

Ask the thread to finish, and wait for the thread to stop.

If the :nowait option is true, then just ask the thread to finish without waiting for it to stop.

When a thread invokes its own finish method, ThreadFinish is raised, unless :nowait is true.



85
86
87
88
89
90
91
92
93
94
95
# File 'lib/clean_thread.rb', line 85

def finish(options={})
  @_cleanthread_mutex.synchronize {
    raise RuntimeError.new("not started") if @_cleanthread_thread.nil?
    @_cleanthread_stopping = true
  }
  unless options[:nowait]
    raise ThreadFinish if @_cleanthread_thread == ::Thread.current
    @_cleanthread_thread.join
  end
  return nil
end

#finishing?Boolean

Return true if the finish method has been called.

Returns:

  • (Boolean)


108
109
110
# File 'lib/clean_thread.rb', line 108

def finishing?
  @_cleanthread_mutex.synchronize { return @_cleanthread_stopping }
end

#joinObject

Wait for the thread to stop.



103
104
105
# File 'lib/clean_thread.rb', line 103

def join
  return @_cleanthread_thread.join
end

#startObject

Start the thread.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/clean_thread.rb', line 41

def start
  @_cleanthread_mutex.synchronize {
    if @_cleanthread_thread.nil?
      @_cleanthread_thread = Thread.new do
        begin
          # Set the Java thread name (for debugging)
          Java::java.lang.Thread.current_thread.name = "#{self.class.name}-#{self.object_id}" if defined?(Java)

          # Set the CleanThread instance (for use with the CleanThread.check_finishing
          # and CleanThread.finishing? class methods
          Thread.current[:clean_thread] = self

          if @_cleanthread_proc.nil?
            main(*@_cleanthread_args)
          else
            @_cleanthread_proc.call(self, *@_cleanthread_args)
          end
        rescue ThreadFinish
          # Do nothing - exit cleanly
        rescue Exception, ScriptError, SystemStackError, SyntaxError, StandardError => exc
          # NOTE: rescue Exception should be enough here, but JRuby seems to miss some exceptions if you do that.
          #
          # Output backtrace, since otherwise we won't see anything until the main thread joins this thread.
          display_exception(exc)
          raise
        ensure
          # This is needed.  Otherwise, the database connections aren't returned to the pool and things break.
          ActiveRecord::Base.connection_handler.clear_active_connections! if defined? ActiveRecord::Base
        end
      end
    else
      raise TypeError.new("Thread already started")
    end
  }
  return nil
end