Open stegmannt opened 13 years ago
I don't know. I use serialport in a multithreaded environment as well. Are you using Ruby 1.9?
I'm having the same issue on OS X Lion with both 1.8.7 and 1.9.3. Writes works but reads doesn't seem to work at all, they just get stuck even if there's data to be read.
I had a similar problem in Windows using 1.8, but I haven't experienced it since. Particular examples?
Hi there,
I'm using SerialPort version 1.1.0, on Ruby 1.9.3p327 on an Archlinux machine running the 3.6.6-1 kernel. I'm using the SerialPort gem within a loop running inside a thread:
device = "/dev/ttyUSB0"
speed = 9600
timeout = 100
sp = SerialPort.new(device, speed)
sp.read_timeout = timeout
t = Thread.new do
while(true)
value = sp.read
puts value
end
end
gets
t.kill
sp.close
It seems the second I attempt to run the SerialPort code within a thread, or attempt to use other ruby classes which make use of threads, the system appears to go into read_timeout and hangs..
I've also tried to use the rufus-scheduler gem to attempt the following:
scheduler.every '1s' do
device = "/dev/ttyUSB0"
speed = 9600
timeout = 100
sp = SerialPort.new(device, speed)
sp.read_timeout = timeout
value = sp.read
puts value
end
Not sure what else to try :/ any ideas ?
I'm seeing a similar lockup on sp.read from a second thread, but in my case it does not appear to matter what the read_timeout value is set to (negative, zero, or positive). The system is Solaris Express 11 running MRI 1.9.2p290, and ruby-serialport compiles and installs without issue.
Here's some code that demonstrates the issue:
require 'serialport'
require 'thread'
rfid = SerialPort.new("/dev/term/0", 9600, 7, 1, SerialPort::NONE)
def read_tags(port)
while 1
puts "Selecting..."
IO::select([port])
puts "Reading..."
segment = port.read
puts "Segment: #{segment}"
end
end
Thread.new do
read_tags rfid
end
while 1
sleep 100
end
If you remove the Thread.new wrapper around "read_tags rfid", the reading loop works as you'd expect. But as written, with the loop running in a separate thread, the IO::select call works correctly (the thread pauses at the select until the remote serial peer produces output) but the port.read following it hangs indefinitely without ever returning any data. (The select is not necessary to reproduce the problem; it's just there to verify the presence of readable data.)
It does not matter which thread executes which component. Putting the sleep loop into a thread and running read_tags on the main thread produces the same behavior. Whatever the underlying issue is, it seems to be triggered just by the existence of multiple threads.
I'm afraid I don't have experience writing extensions for Ruby, but looking over the C code I get the impression that sp.read is inherited directly from IO and that there's nothing ruby-serialport could be actively doing to create a deadlock. So I'm not convinced that the issue is in ruby-serialport. But since it does affect use of the library and may be part of a pattern, I thought I'd mention it here.
Regarding the above, everything works fine for me on ruby-2.0.0-p195. There was substantial revision in the IO library implementation in MRI coming into 2.0.0, so I assume that whatever the underlying issue was, it was addressed by those patches. Again, this is under Solaris, so YMMV.
Very interesting, thanks Garth I'll give this a go later today :)
:+1: working now!
Thanks for the update!
could this issue be closed now then?
There's probably a legitimate issue in MRI 1.9, but I doubt that ruby-serialport is implicated.
@hparra : it sounds like this can be closed now.
I'm having the same issues. Running windows 7, ruby 2.0.0p481 32bit, serialport-1.3.0. I have tried ruby 1.9 and 2.0 64bit.
My script hangs when I try to write after I set up a read on another thread, unless I set a read timeout, in which case it wont hang but still doesn't read any thing at all.
My code WILL WORK if the serial device (arduino) is looping a char every second or so. It seems to keep the serialport rolling along. It seems like some sort of read or write buffer issue. IE from the arduino side:
void setup() {
Serial.begin(9600);
}
void loop() {
//Serial.print("X"); // WITH THESE TWO LINES UNCOMMENTED EVERYTHING WORKS
//delay(500); // Commented out and the serialport gem will hang
while (Serial.available())
ruby::rx(Serial.read(), processCmd); // this bit just (for now) just spits back
// what it recieves, does work when
// above lines are not commented out.
}
I'm confident the micro controller code isn't the issue, just posting the above to try and make it clear what I'm talking about in the paragraph above.
Here's the test ruby script I'm working with:
class Arduino
def initialize(port="COM3", baud=9600)
@serial_port = SerialPort.new(port, baud)#, 8, 1, SerialPort::NONE)
sleep 5
end
def write(cmd)
@serial_port.syswrite cmd
end
def read
@read_thread = Thread.new do
loop do
c = @serial_port.read
if c
yield c
end
sleep 0.005
end
end
end
end
jig = Arduino.new
jig.read do |c|
print c
end
puts "Ready..."
for i in 0..3
x = gets
puts "Sending message"
jig.write "Hello"
puts "Sent message"
end
gets
Again, with periodic 'x' chars from the arduino I get the 'x's and the expected response, with out the periodic 'x's my ruby script will hang on write.
By the way, just tested my code and it works as expected in Linux.
I just ran into the problem with sp.getc not timing out if it's used in a new Thread.
I've tried using Timeout::timeout() but I guess this will break at least on multicore systems, if the block gets killed while getc is processing the input.
Is there any way to workaround/fix this?