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.


Reply via email to