I'm trying to get the ruby curses gem to run with multiple threads (on Windows) to run a serial port:
require 'serialport'
require 'curses'
include Curses
init_screen
start_color
curs_set(0)
noecho
$cont = true
uartThread = Thread.new do
baudRate = 115200
portNo = 17
begin
$port = SerialPort.new(portNo, baudRate, 8, 1, SerialPort::NONE)
rescue
puts "Could not open serial port"
end
while $cont == true
puts $cont
sleep(1)
end
puts "End of thread"
end
begin
$win = Curses::Window.new(0,0,1,2)
refresh
while $cont
key = getch.to_s
case key
when '5'
$cont = false
end
refresh
end
ensure
close_screen
puts "ensured!"
end
puts "Before join"
uartThread.join
puts "After join"
It basically all works fine (this is just the MRE), I just cant get the program to exit properly: Hitting "5" will stop the curses loop execution but the uartThread.join never returns and to console window I ran the program in, becomes unresponsive (to Ctrl+C etc.) and I can only close the entire window. This isn't a huge problem, just incredibly annoying.
The output looks like this:
true
true
true
ensured!
Before join
I know the global variable solution to stop thread execution isn't pretty, but it's just a test script and fine for now. The same thing works perfectly fine if I exclude the curses part and running curses and the serial port thread also works fine, it's just closing the uartThread gracefully that doesn't work. I tried killing the thread or running join(0) to immediately return and just taking out the loop from the uartThread, somehow curses won't allow that thread to run to completion and I have no idea why?
Running ruby 3.1.3p185 in a git bash console (same behavior in the win cmd prompt) on a Win10 machine.
Edit: I did mess around a bit more and found out a bit more.
When using curses, the global variable
$contonly gets written in the main thread not in theuartThreadand so the thread doesn't terminate. However this does work when not using curses.I cant kill other threads when running curses:
puts uartThread.statusuartThread.exitputs uartThread.status
Will print run or sleep both times (again this works without curses).
So I'm guessing I need to somehow make this work singlethreaded...