Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby Pause thread

In ruby, is it possible to cause a thread to pause from a different concurrently running thread.

Below is the code that I've written so far. I want the user to be able to type 'pause thread' and the sample500 thread to pause.

#!/usr/bin/env ruby

# Creates a new thread executes the block every intervalSec for durationSec.
def DoEvery(thread, intervalSec, durationSec)
    thread = Thread.new do
        start = Time.now

        timeTakenToComplete = 0
        loopCounter = 0
        while(timeTakenToComplete < durationSec && loopCounter += 1)

            yield

            finish = Time.now

            timeTakenToComplete = finish - start

            sleep(intervalSec*loopCounter - timeTakenToComplete)    
        end
    end
end

# User input loop.
exit = nil
while(!exit)
    userInput = gets
    case userInput
    when "start thread\n"
        sample500 = Thread
        beginTime = Time.now
        DoEvery(sample500, 0.5, 30) {File.open('abc', 'a') {|file| file.write("a\n")}}
    when "pause thread\n"
        sample500.stop
    when "resume thread"
        sample500.run
    when "exit\n"
        exit = TRUE
    end
end
like image 408
Jean-Luc Avatar asked Nov 05 '12 02:11

Jean-Luc


People also ask

How do you stop a thread in Ruby?

The first way is by using the class method ::stop , to put the current running thread to sleep and schedule the execution of another thread.

Is Ruby multi threaded?

Ruby makes it easy to write multi-threaded programs with the Thread class. Ruby threads are a lightweight and efficient way to achieve concurrency in your code.

What does thread join do in Ruby?

Calling Thread. join blocks the current (main) thread. However not calling join results in all spawned threads to be killed when the main thread exits.

What is thread current Ruby?

Threads are the Ruby implementation for a concurrent programming model. Programs that require multiple threads of execution are a perfect candidate for Ruby's Thread class. For example, we can create a new thread separate from the main thread's execution using ::new.


2 Answers

Passing Thread object as argument to DoEvery function makes no sense because you immediately overwrite it with Thread.new, check out this modified version:

def DoEvery(intervalSec, durationSec)
    thread = Thread.new do
        start = Time.now
        Thread.current["stop"] = false

        timeTakenToComplete = 0
        loopCounter = 0
        while(timeTakenToComplete < durationSec && loopCounter += 1)
            if Thread.current["stop"]
              Thread.current["stop"] = false
              puts "paused"
              Thread.stop
            end

            yield

            finish = Time.now

            timeTakenToComplete = finish - start

            sleep(intervalSec*loopCounter - timeTakenToComplete)

        end
    end
    thread
end

# User input loop.
exit = nil
while(!exit)
    userInput = gets
    case userInput
    when "start thread\n"
        sample500 = DoEvery(0.5, 30) {File.open('abc', 'a') {|file| file.write("a\n")} }
    when "pause thread\n"
        sample500["stop"] = true
    when "resume thread\n"
        sample500.run
    when "exit\n"
        exit = TRUE
    end
end

Here DoEvery returns new thread object. Also note that Thread.stop called inside running thread, you can't directly stop one thread from another because it is not safe.

like image 122
Dfr Avatar answered Sep 22 '22 05:09

Dfr


You may be able to better able to accomplish what you are attempting using Ruby Fiber object, and likely achieve better efficiency on the running system.

Fibers are primitives for implementing light weight cooperative concurrency in Ruby. Basically they are a means of creating code blocks that can be paused and resumed, much like threads. The main difference is that they are never preempted and that the scheduling must be done by the programmer and not the VM.

Keeping in mind the current implementation of MRI Ruby does not offer any concurrent running threads and the best you are able to accomplish is a green threaded program, the following is a nice example:

require "fiber"

f1 = Fiber.new { |f2| f2.resume Fiber.current; while true; puts "A"; f2.transfer; end }
f2 = Fiber.new { |f1| f1.transfer; while true; puts "B"; f1.transfer; end }

f1.resume f2 # =>
  # A
  # B 
  # A
  # B
  # .
  # .
  # .
like image 41
rudolph9 Avatar answered Sep 26 '22 05:09

rudolph9