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
                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.
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.
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.
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.
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.
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
  # .
  # .
  # .
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With