Live data from Hacker News

Ruby core classes aren't thread safe

jstorimer.com

41–47 of 47 posts

Re: Ruby core classes aren't thread safe

#41
post #23
post #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…

I came to this comment thread specifically to point this out, but you beat me to it. It has nothing to do thread safety, and everything to do with atomicity. This is not a single atomic operation, but rather three atomic (and thread-safe) operations which are bound together with the assumption that the entire thing is atomic when it is not. # you might as well imagine this happening original = x[i] new_val = original…

If I understand correctly, this corresponds to `lock` in C#:

    lock (_gate) {
        x[i] --;
    }
At least in C# it is considered preferable to lock on a private field, as opposed to locking on `this`, so nobody else also locks on your instance, potentially causing a deadlock.

I suppose this applies to `@synchronized` in Objective C as well.

I like that .NET Framework also provides some useful atomic methods, including this one:

    Interlocked.Decrement (ref x[i]);
They come in handy.

Re: Ruby core classes aren't thread safe

#42
post #26

Earlier quoted context omitted.

That's not quite true. The language spec can mandate that the -= be atomic (the X86 equivalent is mandating a LOCK).

Totally agreed. Why do I have to lock it myself (even on a high level language like Ruby)? I'm not programming for C!

You only have to do it yourself once you decide to use threads.

And there is not really a way around that. If the language mandated that all primitive operations (for whatever reasonable operation of 'primitive') were atomic, most multi-threaded programs would slow down to a crawl.

Even ignoring that, having atomic primitives is not sufficient to prevent race conditions. Things like "if balance > withdrawal {balance -= withdrawal; ...} need larger ranges of locking, and no compiler is going to tell you how large they have to be.

Re: Ruby core classes aren't thread safe

#43
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.

There is an ISO spec, but it's not really relevant to the future of the language.

Re: Ruby core classes aren't thread safe

#44
post #26

Earlier quoted context omitted.

That's not quite true. The language spec can mandate that the -= be atomic (the X86 equivalent is mandating a LOCK).

Technically it'd have to mandate that []-= be atomic, there's a load from and a store to a k:v collection, not just from and to memory.

> there's a load from and a store to a k:v collection

That is itself a separate specification question: does simple array access trigger full load/store semantics or is it simply returning a reference?

Re: Ruby core classes aren't thread safe

#45
post #30

Earlier quoted context omitted.

The "core collections" - a term you're defining yourself right now however you like, for the record - aren't threadsafe for a reason. They have different performance characteristics in Java! You need two versions of the collections in these languages because of their concurrency and memory models. In Java, using Concurrent/Atomic classes is how you write idiomatic threadsafe code, and it has been for a decade. Bitchi…

Wow, you went way off kilter there mate, I didn't "bitch because the main list types aren't threadsafe", in fact I didn't even emit the slightest criticism (let alone "bitch") on that front as it makes perfect sense, you're the guy getting all butthurt because I note in passing that Java's or C#'s core collections are no safer than Ruby's if you're using them in a stupid manner. Chill and lay off the exclamation poin…

[deleted]

Re: Ruby core classes aren't thread safe

#46
post #44

Earlier quoted context omitted.

Technically it'd have to mandate that []-= be atomic, there's a load from and a store to a k:v collection, not just from and to memory.

> there's a load from and a store to a k:v collection That is itself a separate specification question: does simple array access trigger full load/store semantics or is it simply returning a reference?

Note that it's not a "simple array" here it's an associative one, a map. And of course it's not just access, it's the retrieval of a reference to an immutable cell, you can't just alter it in place unless you are certain no other reference to the cell exists in the system.

Re: Ruby core classes aren't thread safe

#47
post #44

Earlier quoted context omitted.

> there's a load from and a store to a k:v collection That is itself a separate specification question: does simple array access trigger full load/store semantics or is it simply returning a reference?

Note that it's not a "simple array" here it's an associative one, a map. And of course it's not just access, it's the retrieval of a reference to an immutable cell , you can't just alter it in place unless you are certain no other reference to the cell exists in the system.

> Note that it's not a "simple array" here it's an associative one, a map. And of course it's not just access, it's the retrieval of a reference to an immutable cell, you can't just alter it in place unless you are certain no other reference to the cell exists in the system.

This still comes down the question of whether your language preferes references or values: a design decision in-scope for the original question. A language designer might quite reasonably choose to specify that `foo[i] -= 1` means “Get a reference to the object at position i in container foo and tell it to decrement”, in which case the container access is not a concurrency issue except for write / replacing the initial object. This approach can also be implemented atomically in many architectures because it's a simple arithmetic operation rather than retrieving and storing immutable objects.

It would also potentially be easier to scale if threads don't typically update the same elements because you could perform locking at the cell level rather than the entire container.

Post reply on HN