I have just added threads to an existing program using a model I have used before but this time the thread did not execute so I added
Thread.new {puts "thread" }
exit
at the top of the program and it exited without printing anything.
Pointers on diagnosing the problem solicited.
Linux (ubuntu) ruby 2.7
The given code ..
Thread.new {puts "thread" }
exit
.. is not guaranteed to execute the puts. You must join the thread.
t = Thread.new {puts "thread" }
t.join # block until thread finishes
exit
Related
I have 3 methods that do something on the file system but each method changes current directory and I can't use Threading for those since it uses same ruby process and I have racing condition. I found Process.spawn (can't use fork on windows) might be solution but I don't know how to spawn 3 process and call method in each of those.
I tried following as a test, but didn't work
#!/usr/bin/env ruby
def something
puts 'printaj'
end
def nextsomething
puts 'vici'
end
pid1 = Process.spawn(something)
pid2 = Process.spawn(nextsomething)
Process.wait pid1
Process.wait pid2
puts 'both finished'
How about threads and mutex?
semaphore = Mutex.new
a = Thread.new {
semaphore.synchronize {
# do something on the file system
}
}
b = Thread.new {
semaphore.synchronize {
# do something on the file system
}
}
With this code you will run only one operation on file system in the same time.
https://ruby-doc.org/core-2.5.0/Mutex.html
I have a script that runs several child processes using the fork:
def my_fork s
puts "start fork #{s}, pid #{Process.pid}"
sleep s
puts "finish"
end
forks = []
5.times do |t|
forks << fork do
my_fork t+5
end
end
begin
Process.waitall
rescue Interrupt => e
puts "interrupted!"
forks.each{|fr| Process.kill 9, fr}
end
I need the ability to stop the script by pressing Ctrl+C. But pressing time, some processes may be already dead. as it can be verified?
if you do so:
forks.each{|fr| puts fr.exited?; Process.kill 9, fr}
I get an error:
undefined method `exited?' for 27520:Fixnum (NoMethodError)
The result of Fork is the PID, so rather than fr.exited? you would need to get the process status from the process with a PID of fr. Unfortunately, Ruby does not have a good way to get the process status from a PID. See Get process status by pid in Ruby
You can simply rescue the exception if you try to kill the process and it is has already completed.
instead of:
forks.each{|fr| Process.kill 9, fr}
it would be:
forks.each do |fr|
begin
Process.kill 9, fr
rescue Errno::ESRCH
puts "process #{fr} already exited"
end
end
In RSpec, I have function that creates a new thread, and inside that thread performs some action–in my case, calls TCPSocket#readline. Here's the function as it is right now:
def read
Thread.new do
while line = #socket.readline
#TODO: stuff
end
end
end
Due to thread scheduling, my test will fail if written as such:
it "reads from socket" do
subject.socket.should_receive(:readline)
subject.read
end
Currently the only way I know to hack around this is to use sleep 0.1. Is there a way to properly delay the test until that thread is running?
If your goal is to assert the system state is changed by the execution of your second thread, you should join on the second thread in your main test thread:
it "reads from socket" do
subject.socket.should_receive(:readline)
socket_thread = subject.read
socket_thread.join
end
This is a bit of a hack, but here's a before block you can use in case you'd like the thread to yield but be able to call join at the end of the thread.
before do
allow(Thread).to receive(:new).and_yield.and_return(Class.new { def join; end }.new)
end
In my main thread, I am trying to wait for two resources from two separate threads. The way I implemented is as below:
require 'thread'
def new_thread
Thread.current[:ready_to_go] = false
puts "in thread: new thread"
sleep(5)
puts "in thread: sleep finished"
Thread.current[:ready_to_go] = true
sleep(2)
puts "in thread: back to thread again!"
end
thread1 = Thread.new do
new_thread
end
thread2 = Thread.new do
new_thread
end
# the main thread wait for ready_to_go to start
while (!(thread1[:ready_to_go] && thread2[:ready_to_go]))
sleep(0.5)
end
puts "back to main!"
sleep(8)
puts "main sleep over!"
thread1.join
thread2.join
Is there any better way to implement this? I tried to use conditional variables: the two threads signal the conditional variables and the main thread waits for them. But the wait method requires a mutex in my main thread, which I am trying to avoid.
I'm not familiar with Ruby, but the first Google result for "Ruby wait for thread" says:
you can wait for a particular thread to finish by calling that thread's Thread#join method. The calling thread will block until the given thread is finished. By calling join on each of the requestor threads, you can make sure that all three requests have completed before you terminate the main program.
It's generally best to use synchronization methods to wait for something to complete, rather than looping until a particular state is reached.
One easy way would be to get a Queue (let's call it myqueue). It's threadsafe and located in the Thread module
Instead of
Thread.current[:ready_to_go] = true
... do
myqueue.push :ready_to_go
And then your main thread would be:
junk = myqueue.pop # wait for thread one to push
junk = myqueue.pop # wait for thread two to push
# go on with your work
I need to run multiple background threads in a thread pool with timeout.
The scheme is something like:
#!/usr/bin/env ruby
require 'thread'
def foo(&block)
bar(block)
end
def bar(block)
Thread.abort_on_exception=true
#main = Thread.new { block.call }
end
foo {
sleep 1
puts 'test'
}
Why if i run that i get no output? (and no sleep wait?)
The program ends when the main thread ends. You have to wait on the thread created by bar using join:
foo {
sleep 1
puts 'test'
}.join
Try the work_queue gem http://rubygems.org/gems/work_queue/