On Apr 6, 2013, at 20:58 , Eric Wong <[email protected]> wrote:
> Good to know, I hate unnecessary synchronization :)
>
> Just curious, will using shared strings improperly raise a Ruby
> exception, or will it just segfault the VM? I wouldn't even mind the
> latter.
Most probably just seeing mixed up string data. If you're able to crash the VM,
we actually consider that to be a bug. Regardless of races / concurrency
issues, we don't want people to be able to the crash the VM. So it could raise
an exception, lose data, duplicate data, whatever, but no crashes.
If you're able to crash it in this way, please let us know because that means
we should fix that :).
> AFAIK, MRI only uses rb_str_locktmp/rb_str_unlocktmp to detect bugs
> where strings are accidentally shared.
>
> MRI tests a per-string bit and raises immediately if the string is
> already locked by another thread. There's no waiting at all. Since
> this bit is guarded by the GVL, no additional memory barrier is needed
> in MRI.
>
> If Rubinius were to implement it; it'd still need the per-string bit
> flag and use atomic test/set operations. No waiting, but there'll
> need to be memory barriers at least.
Actually this is exactly what happens when an object is only locked by a single
thread and there is no contention. We use CAS to set a locked flag together
with the thread id and only inflate to a full mutex when there is contention on
the lock.
This means locking around non-contended resources is a lot cheaper, but it's
still not free of course.
> Maybe something like this:
>
> # will raise if lock bit is already set
> Rubinius.synchronize(string) { string.set_lock_bit! }
>
> io.read(8192, string)
>
> # will raise if lock bit was not set
> Rubinius.synchronize(string) { string.clear_lock_bit! }
Like I mentioned, if the string is not often contended, the easiest is just to
lock the string itself, since that already does a cheaper CAS locking mechanism
which only inflates when not contended. You can also use Rubinius.try_lock
which will try to lock and return whether it succeeded.
So I would just write this code like this:
Rubinius.synchronize(string) { io.read(8192, string) }
This will be at least as fast as this example, since the example has the
locking overhead + the overhead of adding some lock bits.
--
Dirkjan
--
--
--- !ruby/object:MailingList
name: rubinius-dev
view: http://groups.google.com/group/rubinius-dev?hl=en
post: [email protected]
unsubscribe: [email protected]
---
You received this message because you are subscribed to the Google Groups
"rubinius-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.