Ruby thread.join does not return when using curses gem

58 views Asked by At

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.

  1. When using curses, the global variable $cont only gets written in the main thread not in the uartThread and so the thread doesn't terminate. However this does work when not using curses.

  2. I cant kill other threads when running curses:

    puts uartThread.status

    uartThread.exit

    puts 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...

0

There are 0 answers