Threading Around a Blocking Read - ruby

I'm doing some joystick programming in Ruby on Linux using a Ruby extension which wraps the basic functionality of joystick.h. Getting a joystick event is a blocking read by default, but I don't want that to interrupt the game loop.
Currently I'm hacking around it by making non-blocking calls to the joystick and running that in a really fast loop. That works, but it also makes the script use 100% CPU because I want the joystick events as close to real time as possible.
I'm trying to do something like
input = Thread.new do
while e = joystick.event
#event = e
end
end
main = Thread.new do
while true
sleep 0.1
puts #event
end
end
But even then, the joystick.event call blocks the main thread. Am I totally misunderstanding how Ruby threads work, or how joysticks work on Linux? Or is there a totally different way of approaching this that is better?

I needed to make the read call in the C extension using rb_thread_blocking_region. Works perfectly now!

Related

Why does QSerialPort::writeData start writes with a single-shot timer?

I'm trying to understand Qt's serial port module and I'm not too familiar with how Qt handles asynchronous I/O. On Windows, the QSerialPort::writeData method places the data to be written in a ring buffer and then starts a single-shot QTimer to actually perform the write when its timeout signal fires:
qint64 QSerialPortPrivate::writeData(const char *data, qint64 maxSize)
{
Q_Q(QSerialPort);
writeBuffer.append(data, maxSize);
if (!writeBuffer.isEmpty() && !writeStarted) {
if (!startAsyncWriteTimer) {
startAsyncWriteTimer = new QTimer(q);
QObjectPrivate::connect(startAsyncWriteTimer, &QTimer::timeout, this, &QSerialPortPrivate::_q_startAsyncWrite);
startAsyncWriteTimer->setSingleShot(true);
}
if (!startAsyncWriteTimer->isActive())
startAsyncWriteTimer->start();
}
return maxSize;
}
The readData method doesn't use a timer in this way, instead calling ReadFileEx directly.
What does the single-shot timer accomplish versus just calling WriteFileEx?
There is a special case for a QTimer with an interval of 0: this timer will fire once control returns to the event loop. The implementation on Unix/Linux does something similar, but not using a QTimer, instead having a subclass of QSocketNotifier that will get called when the port is able to be written to. Both of these implementations mean that you will buffer the data and write it out once you get back to the main event loop.
There are two reasons that I can think of for doing this:
There is something different between the POSIX and Win32 serial APIs that require the code to be structured this way. As far as I am aware, this is not the case
What #Mike said in a comment: this will allow for data to be buffered before it is written
The buffering seems like the most likely reason for this, as doing a syscall for each piece of data that you want to write would be a rather expensive operation.

Ruby multithreading

I have code that is running in a manner similar to the sample code below. There are two threads that loop at certain time intervals. The first thread sets a flag and depending on the value of this flag the second thread prints out a result. My question is in a situation like this where only one thread is changing the value of the resource (#flag), and the second thread is only accessing its value but not changing it, is a mutex lock required? Any explanations?
Class Sample
def initialize
#flag=""
#wait_interval1 = 20
#wait_interval2 = 5
end
def thread1(x)
Thread.start do
loop do
if x.is_a?(String)
#flag = 0
else
#flag = 1
sleep #wait_interval
end
end
end
def thread2(y)
Thread.start do
loop do
if #flag == 0
if y.start_with?("a")
puts "yes"
else
puts "no"
end
end
end
end
end
end
As a general rule, the mutex lock is required (or better yet, a read/write lock so multiple reads can run in parallel and the exclusive lock's only needed when changing the value).
It's possible to avoid needing the lock if you can guarantee that the underlying accesses (both the read and the write) are atomic (they happen as one uninterruptible action so it's not possible for two to overlap). On modern multi-core and multi-processor hardware it's difficult to guarantee that, and when you add in virtualization and semi-interpreted languages like Ruby it's all but impossible. Don't be fooled into thinking that being 99.999% certain there won't be an overlap is enough, that just means you can expect an error due to lack of locking once every 100,000 iterations which translates to several times a second for your code and probably at least once every couple of seconds for the kind of code you'd see in a real application. That's why it's advisable to follow the general rule and not worry about when it's safe to break it until you've exhausted every other option for getting acceptable performance and shown through profiling that it's acquiring/releasing that lock that's the bottleneck.

Terminal-based snake game: input thread manipulates output

I'm writing a snake game for the terminal, i.e. output via print.
The following works just fine:
while status[snake_monad] do
print to_string draw canvas, compose_all([
frame,
specs,
snake_to_hash(snake[snake_monad])
])
turn! snake_monad, get_dir
move! snake_monad, specs
sleep 0.25
end
But I don't want the turn!ing to block, of course. So I put it into a new Thread and let it loop:
Thread.new do
loop do
turn! snake_monad, get_dir
end
end
while status[snake_monad] do
...
# no turn! here
...
end
Which also works logically (the snake is turning), but the output is somehow interspersed with newlines. As soon as I kill the input thread (^C) it looks normal again.
So why and how does the thread have any effect on my output?
And how do I work around this issue? (I don't know much about threads, even less about them in ruby. Input and output concurrently on the same terminal make the matter worse, I guess...)
Also (not really important): Wanting my program as pure as possible, would it be somewhat easily possible to get the input non-blockingly while passing everything around?
Thank you!
You don't want non-blocking IO - you want unbuffered IO.
There's no need for threads, here - you just need to put your terminal into the right mode and then wait for the keypress on the main event loop.
Here's a completely ridiculous example.
require 'io/wait'
def ping
term = `stty -g`
`stty raw -echo cbreak`
loop do
if STDIN.ready?
#command thy snake!
ret = STDIN.getc
end
if ret
#process the snake command if there was one
STDOUT.write("you told the snake to #{ret}\n")
else
#slither around bitin' fools and hustling apples.
end
end
ensure
`stty #{term}`
end
I found a dirty solution:
I just had to add a carriage return (\r) after each newline in the to_string function, so everything that gets printed after it will be overwritten. Since it was a newline, it loses its effect. Everything seems fine now.
But I'd much rather know why this happens and fix it (if possible) cleanly.

Is it possible to ensure that threaded code doesn't have side effects in Ruby?

Data safety and GIL removal mentions that if you don't have the Giant Interpreter Lock in place, you increase the risk of race conditions. The blog post gave the following example:
# As noted in the blog post, this'll work correctly in MRI Ruby (1.8 or 1.9)
# but may or may not work correctly in Rubinius 2.0 or JRuby
#array, threads = [], []
4.times do
threads << Thread.new { (1..100_000).each {|n| #array << n} }
end
threads.each{|t| t.join }
puts #array.size
One approach I'd take to making the code thread safe is to do functional programming and not have code within the thread modify objects/variables that weren't created within the thread:
threads = 4.times.map do
Thread.new do
sub_array = []
# Modifying sub_array is fine, because it was created by this thread
(1..100_000).each {|n| sub_array << n}
sub_array
end
end
puts threads.map(&:value).flatten(1).size
# Or (and don't forget nil!)
# array = threads.map(&:value).flatten(1) ; nil
# puts array.size
Is it possible to specify that a thread isn't allowed to modify objects/variables that don't "belong" to it, and raise a warning or exception if it does?
Assume that the threaded code doesn't do anything spectacularly pathological like calling ObjectSpace.each_object.
I don't know of a way to limit Ruby's access to things in any capacity other than the long-standing tradition of forking out a new process that is independent. Most languages are like this with very few exceptions, with strictly functional languages being in that set as you point out.
The most responsible approach here is to either use Mutex locking, or to create classes that are thread-safe by keeping data isolated and independent. This requires careful design, but if done right your threaded application is nearly as simple as a standard one.

How to get data to a running ruby process?

I have a datastore with a cache and a db, simple. The tricksy part is that I want a way to control if the the datastore hits the db in a real-time way. That is to say while the process is running I want to be able to toggle if it's connected to the db or not.
I looked into env variables, but it doesn't seem like those get updated as the process runs. Is there a simple way to get a bit from the command line into the running process, or do I just need to rely on ops being able to drop the db listeners in case of disaster?
Note that this is all being done in vanilla ruby - not ruby on rails.
Thanks!
-Jess
I think you can use named pipes for simple communication:
#pipes.rb:
f = File.open 'mypipe', 'r+'
loop do
begin
s = f.read_nonblock 1
rescue Exception
end
case s
when '0'
puts 'Turn off DB access!'
when '1'
puts 'Turn on DB access!'
end
sleep 1
end
And you can control your db access externally by writing to the named pipe:
jablan-mbp:dev $ echo 101 > mypipe
Which results in:
jablan-mbp:dev $ ruby pipes.rb
Turn on DB access!
Turn off DB access!
Turn on DB access!
A shared-memory strategy might be worth considering. Assuming you're running on a POSIX system, check out mmap for memory-mapped files, and SysVIPC for message queues, semaphores, and shared memory.
Assuming *NIX, have you considered signals? (kill -HUP pid) - http://ruby-doc.org/core/classes/Signal.html

Resources