Skip to content

Adding stack helper methods (Old)

rscottm edited this page Oct 8, 2011 · 1 revision

Idea one

# Options:
#   :stack_size
#   :when_done   - block performed on the calling thread
#   :when_failed - block performed on the calling thread
#   :wait        - wait for the block to complete
def do_in_thread(args = {}, &block) 
  handler = Java::android.os.Handler.new if args[:when_done] or args[:when_failed] 
  thread_proc = Proc.new do 
    begin 
      block.call 
      handler.post(args[:when_done]) if args[:when_done] 
    rescue 
      handler.post(args[:when_failed]) if args[:when_failed] 
    end 
  end 
  if args[:stack_size] 
    t = java.lang.Thread.new(nil, thread_proc, nil,  args[:stack_size]) 
  else 
    t = java.lang.Thread.new(nil, thread_proc) 
  end
  t.join if args[:wait]
  t
end

Usage
# Run some code with large stack and get the result
result1 = nil
do_in_thread(:wait => true){result1 = some_library_call}
do_in_thread{result1 = some_library_call}.join

# Run some code with large stack and get the result.  Specify stack size.
result2 = nil
with_large_stack(256){result2 = some_other_library_call}
do_in_thread(:stack_size => 256, :wait => true){result2 = some_other_library_call}
do_in_thread(:stack_size => 256){result1 = some_library_call}.join

# Run some code in the background with large stack
result3 = nil
do_in_thread(:stack_size => 256) do
  stuff_requiring_large_stack
  result3 = 42
end

# Run some code in the background with large stack then update the calling thread with the result.
result4 = nil
do_in_thread(:stack_size => 256, :when_done => proc{result4 = 42}) do
  stuff_requiring_large_stack
end

# Run some code in the background with large stack then update the calling thread with the result, including exceptions.
status_view = text_view
do_in_thread(:stack_size => 256, :when_done => proc{status_view.text = 'SUCCESS'}, :when_failed => proc{status_view.text = 'FAILED'}) do
  stuff_requiring_large_stack
end

Idea two
class Object 
  def with_large_stack(stack_size_kb = 64, &block) 
    result = nil 
    t = Thread.with_large_stack(&proc{result = block.call}) 
    t.join 
    result 
  end 
end 
class Thread 
  def self.with_large_stack(stack_size_kb = 128, &block) 
    t = java.lang.Thread.new(nil, block, "block with large stack", stack_size_kb * 1024) 
    t.start 
    t 
  end 
end

Usage

# Run some code with large stack and get the result
result1 = with_large_stack{some_library_call}

# Run some code with large stack and get the result.  Specify stack size.
result2 = with_large_stack(256){some_other_library_call}

# Run some code in the background
Thread.start do
  stuff_run_in_the_background
end

# Run some code in the background with large stack
Thread.with_large_stack do
  stuff_requiring_large_stack
end

# Run some code in the background with large stack specifying stack size
Thread.with_large_stack(128) do
  stuff_requiring_large_stack
end

# Run some code in the background with large stack then update the calling thread with the result.
result3 = nil
Thread.with_large_stack do
  stuff_requiring_large_stack
  run_on_ui_thread{result3 = 42}
end

# Run some code in the background with large stack then update the calling thread with the result, including exceptions.
status_view = text_view
Thread.with_large_stack(256) do
  begin
    stuff_requiring_large_stack
    run_on_ui_thread{status_view.text = 'SUCCESS'}
  rescue
    run_on_ui_thread{status_view.text = 'FAILED'}
  end
end

Idea three

Over designed hybrid. Assumes two main use cases: 1) execute code in another thread, and 2) execute code needing large stack. Don’t need all of these calls. Could just select a subset.

class Object
  def eval_with_large_stack(str, stack_size_kb = 128) 
    call_in_thread(stack_size_kb, &proc{eval(str)})
  end 

  def eval_in_thread(str, stack_size_kb = 16) 
    call_in_thread(stack_size_kb, &proc{eval(str)})
  end 

  def call_with_large_stack(stack_size_kb = 128, &block) 
    call_in_thread(stack_size_kb, &block)
  end

  def call_in_thread(stack_size_kb = 16, &block) 
    result = nil
    java.lang.Thread.call(stack_size_kb, &proc{result = block.call}).join
    result 
  end
end

class Proc 
  def call_in_thread(stack_size_kb = 16) 
    java.lang.Thread.call(stack_size_kb, &self)
  end 

  def call_with_large_stack(stack_size_kb = 128) 
    call_in_thread(stack_size_kb, &self)
  end 
end

java.lang.Thread.class_eval do
  def self.eval(str, stack_size_kb = 16) 
    call(stack_size_kb, &proc{eval(str)})
  end 

  def self.call(stack_size_kb = 16, &block) 
    t = java.lang.Thread.new(nil, block, "block with stack #{stack_size_kb}", stack_size_kb * 1024) 
    t.uncaught_exception_handler = proc{|t, ex|}
    t.start 
    t 
  end 
end

Usage

# Run code in another thread
proc{code_to_not_block_on}.call_in_thread

# or
Thread.call{code_to_not_block_on}

# or (blocks)
result = call_in_thread{code_to_block_on}

# Run some code with large stack and get the result
result1 = call_with_large_stack{some_library_call}

# Run some code with large stack and get the result.  Specify stack size.
result2 = call_with_large_stack(256){some_other_library_call}

# Run some code in the background with large stack
proc{stuff_requiring_large_stack}.call_with_large_stack

# Run some code in the background with large stack then update the calling thread with the result.
p = proc do
  stuff_requiring_large_stack
  run_on_ui_thread{toast("result = 42")}
end
p.call_with_large_stack

# Run some code in the background with large stack then update the calling thread with the result, including exceptions.
status_view = text_view
p = proc do
  begin
    stuff_requiring_large_stack
    run_on_ui_thread{status_view.text = 'SUCCESS'}
  rescue
    run_on_ui_thread{status_view.text = 'FAILED'}
  end
end
p.call_with_large_stack(256)
Clone this wiki locally