Threading in Ruby gets a bit of a bad rap. While MRI doesn't support full threads, only one Ruby thread can be actively running at the same time, other Ruby implementations (such as JRuby) can run threads fully concurrently, and even MRI supports concurrency in IO-bound tasks. The following are three articles that may help you understand threading in Ruby.
- Threads - We take a look at the basics of threading in Ruby. How to create threads and clean up after them.
- Thread pools - We do something a bit more practical and look at how to create a thread pool to concurrently perform a number of tasks without creating a new thread for each one.
- Mutexes - Race conditions. They're bad, but they're impossible to avoid without mutexes. If you're working with threads, you need to know about mutexes.
Since we're talking about threads, we have to talk about mutexes. A Mutex is the only practical way to prevent race conditions (where more than one thread tries to access a resource at the same time). A mutex is not a complicated (though it is nuanced) thing, and Ruby implements Mutexes in a rather simple way.
A common pattern in programs that must complete a large number of jobs is to use a thread pool, a type of producer/consumer model. Say, for example, you have to download 500 files. One way to do this is to take the URL for each file in turn, download the file, and move onto the next, but that's very slow. Another way is to fire up 500 threads, one of each file and just let the OS sort it out but that's both inefficient and rude (you shouldn't "thrash" we servers like that). So, instead, make a thread pool. You have 500 files to download, but you only want 3 to download concurrently. What you really want is a thread pool.
Ruby does have threads, however the threading support in MRI (the most widely used Ruby interpreter) is not complete. It supports concurrency for IO-bound tasks, but since only one Ruby thread may execute at a time, CPU-bound tasks cannot be run concurrently on Ruby's MRI interpreter. Nonetheless, Ruby does have threads, and this is how you use them.
Ruby has its roots in Perl (or at least one of its roots) and conditional assignments are one Perlism that Ruby brought along with it. A conditional assignment allows you to assign (or not assign) a value to a variable depending on the truthiness of the value currently held in the variable. Though these constructs can be replaced with simple conditional statements, they're still in wide use today.
Signals are an interprocess communication primitive used in UNIX-like operating systems (mostly Linux and OS X in the Ruby world). They're used primarily to inform a program it's being shut down. There are things you can do to prevent the shut down, however, and other uses for signals than shutting preventing a shut down.
Threading in Ruby has always been a bit of a nonstarter. Early on, there was the global interpreter lock, and even now concurrency is not really a thing in MRI (though it's truly concurrent on jRuby). However, there is another concurrency model: cooperating multitasking. It's not used much, but it can be an interesting way to segment you code. Cooperating multitasking is implemented in Ruby using Fibers.
2048 is the newest game to really go viral. No one even remembers Flappy Bird anymore, now it's all 2048 all day long. So what is 2048? It's a sliding puzzle game you can play here. And it's open source and up on Github. It can be summed up as this: you have a 4x4 grid of numbers and empty spaces. Slide all the tiles in any direction and any times of the same value that touch combine into a single tile. Your objective is to make larger and larger tiles, all the way up to (and beyond) 2048. Spend a few minutes playing the game and you'll see, it's a simple game.
Read the whole series at Cloning 2048 in Ruby
All the important methods were already talked about in the previous articles. We really need to talk about spawning new cells and seeing if we've met the game over condition though.
Read more at: The Final Few Methods
The slide method is the core of the whole 2048 game. It slides all the rows to the left, collapsing any empty tiles and combining any adjacent tiles with the same value. Remember that this method onlyslides the puzzles to the left. In order to slide the puzzle to the right, you need to rotate the puzzle twice (so it's essentially upside down, and left is right), slide the tiles and rotate the puzzle twice again. Similarly, to move up and down you rotate, slide and rotate again (always completing four rotations total).
Read more at: The Core Algorithm