Rubyists generally tend to shy away from multi-threaded code.
Cognitive overload, horror stories of threading bugs, and MRI's lack of native threading support are probably the reasons, but these are powerful constructs that every developer should understand. We'll tour the basic synchronization primitives that Ruby provides, and I'll show you where each is appropriate, covering potential pitfalls and hazards along the way. We'll see the strengths and limitations of the way MRI, Rubinius, and JRuby run our multithreaded code, and the implications that that has on our code's progress.
10. Mutexes
Easiest way to synchronize things in Ruby
Create a Mutex
Call Mutex.synchronize, and at most one thread will be
able to run the content of the block
11. Condition Variable
Allows us to wait for certain conditions to become true
before continuing, rather than burning CPU doing
nothing
Allows threads to immediately give up their lock so
another thread can make that condition true
19. Monitors
Think Mutex + Condition Variable
Provides a better structure
Allows for recursive locking
Threads enter a waiting queue and are signaled by
threads that currently have the monitor
20. Semaphores
Basically variables handled by the runtime/OS
Earliest formulation of synchronization
Two types: counting and binary
Two basic operations: P & V
Ruby doesn’t provide them… for good reason
21.
22. Software Transactional
Memory
No first class support, gems have become stale
Allows writers to take an optimistic view of the world
Onus is on readers to clean up the writers' mess
26. MRI's Threads
One pthread for every Thread.new
…but every thread has to obtain a VM-wide Mutex,
which is the GIL or Global Interpreter Lock
Better for downloading Tweets while writing ones a user
cares about on a Socket, than for mining your
Cryptocurrency of choice
27. Rubinius & jRuby’s Threads
One thread per Thread.new
Rubinius and jRuby have no Global Interpreter Lock, so
they’re generally going to be better if your work is CPU
bound
28. The Safest Path to
Concurrency
Don't do it
If you must do it, don't share data across threads
If you must share data across threads, don't share
mutable data
If you must share mutable data across threads,
synchronize access to that data
Source: Working with Ruby Threads - Jesse Stormier