Live data from Hacker News

Ruby core classes aren't thread safe

jstorimer.com

11–20 of 47 posts

Re: Ruby core classes aren't thread safe

#11
post #9
post #5

This still doesn't explain why the MRI implementation is accidentally threadsafe. Why doesn't the interpreter switch threads after reading the value from the hash but before storing the updated value?

Due to the Global Interpreter Lock (GIL), your whole script is wrapped in one giant mutex. That means that you don't have code running in true parallel, so the data is not corrupted as it is in JRuby and Rubinius (which both implement real, true, parallel threads).

Not sure why someone chose to downvote this to 0, but here's how the OP put it:

The global lock is a feature of MRI that basically wraps a big mutex around all of your code. That's right, even if you're using multiple threads on a multi-core CPU, if your code is running on MRI it will not run in parallel.

Re: Ruby core classes aren't thread safe

#12
post #7

Under the semantics described here, Java or C# core classes aren't "thread-safe" either and I'd expect the vast majority of standard libraries to completely fail the test (potential winners: Clojure using an immutable collection bound on an atom, as they have compare-and-swap semantics; and probably Haskell somehow), the example code requires performing the following actions atomically: * Loading an instance-local co…

> and probably Haskell somehow

By design - pure values are always thread safe.

Re: Ruby core classes aren't thread safe

#13
post #11
post #9

Earlier quoted context omitted.

Due to the Global Interpreter Lock (GIL), your whole script is wrapped in one giant mutex. That means that you don't have code running in true parallel, so the data is not corrupted as it is in JRuby and Rubinius (which both implement real, true, parallel threads).

Not sure why someone chose to downvote this to 0, but here's how the OP put it: The global lock is a feature of MRI that basically wraps a big mutex around all of your code. That's right, even if you're using multiple threads on a multi-core CPU, if your code is running on MRI it will not run in parallel.

OP is wrong, MRI will release the GIL (and yield to other threads) on IO and after running a bit (which can yield convoy effect actually lowering the performances). C extensions can also release the GIL when not manipulating VM structures.

Technically the GIL is there to protect the VM's internal state, so its operational semantics are that it's taken and released for each bytecode instruction.

However the efficiency would stink (short of awesome automatic lock elision or merging), so GIL-based VMs usually have a higher threshold, either based on some sort of instructions count (which may or may not map 1:1 to bytecode instructions) or an internal "wall clock" timer. I think MRI's the latter but don't quote me on it.

Re: Ruby core classes aren't thread safe

#14
post #12
post #7

Under the semantics described here, Java or C# core classes aren't "thread-safe" either and I'd expect the vast majority of standard libraries to completely fail the test (potential winners: Clojure using an immutable collection bound on an atom, as they have compare-and-swap semantics; and probably Haskell somehow), the example code requires performing the following actions atomically: * Loading an instance-local co…

> and probably Haskell somehow By design - pure values are always thread safe.

Pure values are not really relevant: you still need to update a binding somewhere to synchronize, and that's sufficient for your race. The clojure example wouldn't be safe if atoms weren't compare-and-set: have collection state A, thread one applies A->B, thread two applies A->C, the two threads set the atom (atomically but not CAS) and an increment has been lost even though all values are pure.

Re: Ruby core classes aren't thread safe

#15
post #3

Does the spec mandate thread safety? (I guess I should ask if there's a spec or is MRI the reference implementation)

AFAIK there is no spec. MRI is the reference implementation, but many things are experimental or intentionally unspecified.

Given that MRI ships with a GIL, the only core classes that are intentionally aware of multi-threading concerns are Mutex, ConditionVariable, and Queue.

Re: Ruby core classes aren't thread safe

#16
post #7

Under the semantics described here, Java or C# core classes aren't "thread-safe" either and I'd expect the vast majority of standard libraries to completely fail the test (potential winners: Clojure using an immutable collection bound on an atom, as they have compare-and-swap semantics; and probably Haskell somehow), the example code requires performing the following actions atomically: * Loading an instance-local co…

A better title might have been, "true concurrent execution may reveal problems in your code that a GIL has hidden."

Having worked on a JVM port of a similar language and standard library what is most surprising is how much will still work in real world situations even when fundamental parts are not thread safe. It requires careful insertion of locks, and some quite heavy multithreaded testing to find and fix those problems, and that time may be better spent implementing new thread safe alternatives (or simply exposing the java concurrent collections) which encourage the programmer to write thread safe code, and putting locks in at the application level to fix concurrency issues.

Re: Ruby core classes aren't thread safe

#17
post #7

Under the semantics described here, Java or C# core classes aren't "thread-safe" either and I'd expect the vast majority of standard libraries to completely fail the test (potential winners: Clojure using an immutable collection bound on an atom, as they have compare-and-swap semantics; and probably Haskell somehow), the example code requires performing the following actions atomically: * Loading an instance-local co…

A better title might have been, "true concurrent execution may reveal problems in your code that a GIL has hidden." Having worked on a JVM port of a similar language and standard library what is most surprising is how much will still work in real world situations even when fundamental parts are not thread safe. It requires careful insertion of locks, and some quite heavy multithreaded testing to find and fix those pr…

> A better title might have been, "true concurrent execution may reveal problems in your code that a GIL has hidden."

Indeed (and as many Python developers have discovered trying to run their code on pypy, deterministic "garbage collection" schemes such as refcounting may do the same with resource leaks)

Re: Ruby core classes aren't thread safe

#18
It's not that Arrays are not thread safe; it's just that the code was written in a non-thread-safe way.

Writing

  x[i] -= 1
actually means

  x[i] = x[i] - 1
So, there's a read, a subtraction, and a write, and they all happen sequentially. Since they are not in a transaction or protected by a mutex, nothing guarantees that other thread don't mutate `x[i]` in the mean time.

This has nothing to do with Ruby, and nothing to do with multicore, either. Even on a single CPU core, threads might interleave and cause unexpected behavior.

Re: Ruby core classes aren't thread safe

#19
post #11

Earlier quoted context omitted.

Not sure why someone chose to downvote this to 0, but here's how the OP put it: The global lock is a feature of MRI that basically wraps a big mutex around all of your code. That's right, even if you're using multiple threads on a multi-core CPU, if your code is running on MRI it will not run in parallel.

OP is wrong, MRI will release the GIL (and yield to other threads) on IO and after running a bit (which can yield convoy effect actually lowering the performances). C extensions can also release the GIL when not manipulating VM structures. Technically the GIL is there to protect the VM's internal state, so its operational semantics are that it's taken and released for each bytecode instruction. However the efficiency…

Correct. Later on I say:

  There are some very specific caveats that MRI makes for concurrent IO. If you have one thread that's waiting on IO (ie. waiting for a response from the DB or a web request), MRI will allow another thread to run in parallel.

Re: Ruby core classes aren't thread safe

#20
post #7

Under the semantics described here, Java or C# core classes aren't "thread-safe" either and I'd expect the vast majority of standard libraries to completely fail the test (potential winners: Clojure using an immutable collection bound on an atom, as they have compare-and-swap semantics; and probably Haskell somehow), the example code requires performing the following actions atomically: * Loading an instance-local co…

> Under the semantics described here, Java or C# core classes aren't "thread-safe" either and I'd expect the vast majority of standard libraries to completely fail the test (potential winners: Clojure using an immutable collection bound on an atom, as they have compare-and-swap semantics; and probably Haskell somehow)

Java's standard library includes Doug Lea's famous java.util.concurrent package written as part of JSR 166, which according to (http://jcp.org/en/jsr/detail?id=166) was finally released in late 2004. Never wrote C#, but I started typing [C# concurrent] into Google and it autocompleted and instantly searched for [C# ConcurrentDictionary], the first result being: http://msdn.microsoft.com/en-us/library/dd287191.aspx .

Post reply on HN