Forum: Ruby basic threading question: can ruby use real threads?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
9dec3df8319c613f6f4f14a27da0fdb4?d=identicon&s=25 Kyle Schmitt (Guest)
on 2007-05-08 22:53
(Received via mailing list)
I've read somewhere, and would love for it to be wrong, that ruby
doesn't use real threads, that it handles it's threads internally.  Is
that true?  If it is true, will that still be true when ruby 1.9, or
2.0 comes out?

For many systems this isn't a big deal one way or the other, since
they only have one physical processor.  Luckily(?) pretty much all my
systems have two procs. (Two real processors, not HT, but that's a
debate for another day.)  I'd like to write some threaded ruby code,
and have it spread across my cpus, share data structures etc.

I'm used to pthreads in UNIX systems :) so I'd _really_ like it if I
could do the same type of things I've done before, just in a rubyish
sort of way.  Setting up a shared memory area and all that jazz that
you had to do for forking really doesn't sound like a fun, especially
when the point of the code I wanna write _is_ for fun.

Thanks,
         Kyle
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-05-08 22:59
(Received via mailing list)
On May 8, 2007, at 3:52 PM, Kyle Schmitt wrote:

> I've read somewhere, and would love for it to be wrong, that ruby
> doesn't use real threads, that it handles it's threads internally.  Is
> that true?  If it is true, will that still be true when ruby 1.9, or
> 2.0 comes out?

This was recently discussed in detail by the creators:

http://blog.grayproductions.net/articles/2007/04/2...
episode-iii

James Edward Gray II
9dec3df8319c613f6f4f14a27da0fdb4?d=identicon&s=25 Kyle Schmitt (Guest)
on 2007-05-08 23:04
(Received via mailing list)
Sweet, thanks for the link!
9dec3df8319c613f6f4f14a27da0fdb4?d=identicon&s=25 Kyle Schmitt (Guest)
on 2007-05-08 23:36
(Received via mailing list)
OK, so I'm reading that article, and I'm getting three things form it:
YARV uses native threads.
YARV doesn't run them simultaneously.
YARV will eventually run them simultaneously.

Good enough for me, I'll just hope that writing threaded code doesn't
change to much with ruby2.0/YARV.

--Kyle
A57dbd9d858a6995b9ca4110d871a256?d=identicon&s=25 unknown (Guest)
on 2007-05-08 23:40
(Received via mailing list)
Quoting Kyle Schmitt <kyleaschmitt@gmail.com>:

> I've read somewhere, and would love for it to be wrong, that ruby
> doesn't use real threads, that it handles it's threads internally. Is
> that true?

You have heard correctly and yes it is a pain.
F0afd024e17c0c4753aa8d618ba9bb0f?d=identicon&s=25 Marcin Raczkowski (Guest)
on 2007-05-09 18:00
(Received via mailing list)
On Tuesday 08 May 2007 21:34, Kyle Schmitt wrote:
> OK, so I'm reading that article, and I'm getting three things form it:
> YARV uses native threads.
> YARV doesn't run them simultaneously.
> YARV will eventually run them simultaneously.
>
> Good enough for me, I'll just hope that writing threaded code doesn't
> change to much with ruby2.0/YARV.
>
> --Kyle

well you can use fastthreads gem (part of mongrel)
also you can fork your script ^^ threads usually execute on same
processor
AFIK, that's why if you want to use 2 processors you have to fork your
scripts, and if you need comunication between them consider using drb.

very good gem is slave - it makes creating new processes super easy - it
provides easy way to comunicate, so you can create 4-6 new processes
each
will get data to compute from mother process and the'll use both
processors

sorry for lots of randomness and strange grammar - to much coffeine
to sumarize - read rdoc for gems:
- fasthread(s)
- slave(s)
(i never remember if they are plurar or singular)
912c61d9da47754de7039f4271334a9f?d=identicon&s=25 MenTaLguY (Guest)
on 2007-05-09 20:28
(Received via mailing list)
On Thu, 10 May 2007 01:00:04 +0900, Marcin Raczkowski
<swistak@mailx.expro.pl> wrote:
> well you can use fastthreads gem (part of mongrel)

fastthread just makes the locking primitives from thread.rb a little
faster; it doesn't otherwise affect the operation of Ruby threads.
Additionally, it is applicable only to Ruby 1.8, not YARV/1.9.

-mental
F0afd024e17c0c4753aa8d618ba9bb0f?d=identicon&s=25 Marcin Raczkowski (Guest)
on 2007-05-09 20:58
(Received via mailing list)
On Wednesday 09 May 2007 18:27, MenTaLguY wrote:
> On Thu, 10 May 2007 01:00:04 +0900, Marcin Raczkowski
<swistak@mailx.expro.pl> wrote:
> > well you can use fastthreads gem (part of mongrel)
>
> fastthread just makes the locking primitives from thread.rb a little
> faster; it doesn't otherwise affect the operation of Ruby threads.
> Additionally, it is applicable only to Ruby 1.8, not YARV/1.9.
>
> -mental

I didn't say it makes use of POSIX threads - i just recomended it
becouse they
are well ... faster.

only thing right now that'll let you use botht procesors is fork
9dec3df8319c613f6f4f14a27da0fdb4?d=identicon&s=25 Kyle Schmitt (Guest)
on 2007-05-09 21:04
(Received via mailing list)
If you fork, is there even a way to create objects that are shared
between the two forks?  Or do you have to rely on rpc/ipc stuff
instead?


If someone were to... write a c extension who's objects were threaded,
via pthreads, would it be a nightmare?

Even just typing that line almost scares me....but I can think of some
clean(ish?) ways of doing it.  I'm just worried I'd loose the rubyness
of the thing if I did it that way.

Thanks,
          Kyle
E7559e558ececa67c40f452483b9ac8c?d=identicon&s=25 Gary Wright (Guest)
on 2007-05-09 21:21
(Received via mailing list)
On May 9, 2007, at 2:57 PM, Marcin Raczkowski wrote:
> I didn't say it makes use of POSIX threads - i just recomended it
> becouse they
> are well ... faster.
>
> only thing right now that'll let you use botht procesors is fork

Just my opinion but my default choice would be fork when I need
concurrency rather than threads.  The main reason is that it forces you
to be explicit in how you structure the communication between processes.
One process can't inadvertently change the state of another.
On a multi-processor box you'll get IO multiplexing and real CPU
concurrency automatically with fork.

Some problems can't be partitioned easily into separate addresses
spaces,
in which case threads are a better choice.  Even then I might consider
using shared memory among cooperating processes first.

I realize that the Unix fork/exec model of processes doesn't quite apply
in the Windows environment. Anecdotal evidence makes me think that
Windows programmers tend to reach for threads as a multi-tasking
solution
more often than Unix programmers.

One more observation.  The desire for real concurrency using multiple
processors is great for problems that can be cleanly partitioned, but if
you have a problem that requires concurrent access to shared data then
you'll have to keep in mind the memory/cache contention that will be
created when processing is distributed across multiple processors (via
processes or threads).

Gary Wright
912c61d9da47754de7039f4271334a9f?d=identicon&s=25 MenTaLguY (Guest)
on 2007-05-09 21:36
(Received via mailing list)
On Thu, 10 May 2007 04:03:57 +0900, "Kyle Schmitt"
<kyleaschmitt@gmail.com> wrote:
> If you fork, is there even a way to create objects that are shared
> between the two forks?  Or do you have to rely on rpc/ipc stuff
> instead?

Totally RPC.  You could use DRb to do this in a Rubyesque fashion.

It's worth noting that no matter _what_ threading approach you use, it's
absolutely best to minimize the number of objects shared between
threads.

> If someone were to... write a c extension who's objects were threaded,
> via pthreads, would it be a nightmare?

Yes, somewhere between nightmare and flesh-rending terror.  At least if
you're
planning on manipulating Ruby objects from each thread.

You might want to consider using JRuby instead.  It's compatible enough
with MRI
that it runs Rails, and it uses "real" threads for multi-CPU goodness.

-mental
9dec3df8319c613f6f4f14a27da0fdb4?d=identicon&s=25 Kyle Schmitt (Guest)
on 2007-05-09 23:59
(Received via mailing list)
Manipulating ruby objects from inside the threads would be the idea in
some cases I'm thinking of... so it looks like JRuby until YARV gets
concurrent threads... and ooh do I hope it does.

Will the threading interface be drastically different between
MRI/JRuby/YARV? IE does anyone know if I code on MRI will it
automatically use real threads on JRuby, or will I have to re-code
some parts to get that?

Thanks again,
 Kyle
912c61d9da47754de7039f4271334a9f?d=identicon&s=25 MenTaLguY (Guest)
on 2007-05-10 00:06
(Received via mailing list)
On Thu, 10 May 2007 06:59:33 +0900, "Kyle Schmitt"
<kyleaschmitt@gmail.com> wrote:
> does anyone know if I code on MRI will it automatically use real threads on JRuby,

Yes.

The APIs are the same between MRI and JRuby, though JRuby deliberately
hedges
on the implementation of certain unsafe features like Thread#kill,
Thread#raise,
and Thread.critical=.

-mental
934180817a3765d132193a5428f99051?d=identicon&s=25 Sylvain Joyeux (Guest)
on 2007-05-10 08:41
(Received via mailing list)
> The APIs are the same between MRI and JRuby, though JRuby deliberately
> hedges on the implementation of certain unsafe features like
> Thread#kill, Thread#raise, and Thread.critical=.
Thread#raise, "unsafe" ? It is the most useful thread-related
functionality
I've seen since I'm using threads ! It allows for instance to handle
failing rendezvous the proper way (by using exceptions).

Could you tell us why you think it is "unsafe" ?
4feed660d3728526797edeb4f0467384?d=identicon&s=25 Bill Kelly (Guest)
on 2007-05-10 09:10
(Received via mailing list)
From: "Sylvain Joyeux" <sylvain.joyeux@polytechnique.org>
>
>> The APIs are the same between MRI and JRuby, though JRuby deliberately
>> hedges on the implementation of certain unsafe features like
>> Thread#kill, Thread#raise, and Thread.critical=.
> Thread#raise, "unsafe" ? It is the most useful thread-related functionality
> I've seen since I'm using threads ! It allows for instance to handle
> failing rendezvous the proper way (by using exceptions).
>
> Could you tell us why you think it is "unsafe" ?

Hi,

I'm not sure if this is what MenTaLGuY meant, but one way that
Thread#raise is unsafe, is that it can raise an exception in the
specified thread while that thread is executing an 'ensure' block.

This can cause a failure of critical resources to be cleaned up
correctly, such as locks on mutexes, etc., as some or all of the
code in the ensure block is skipped.

I first ran into this when I tried to use timeout{} to implement
a ConditionVariable#timed_wait, like:

  require 'thread'
  require 'timeout'
  class ConditionVariable
    def timed_wait(mutex, timeout_secs)
      timeout(timeout_secs) { wait(mutex) }   # THIS IS UNSAFE
    end
  end

Note that 'timeout' functions by creating a temporary new thread
which sleeps for the duration, then raises an exception in the
'current' thread that invoked timeout.

If the timeout raises its exception at an unlucky moment, the
various internals of ConditionVariable#wait and Mutex#synchronize
that depend on ensure blocks to restore their class invariants are
skipped, resulting in nasty things like a permanently locked mutex.

Not fun... :(


Regards,

Bill
Ede2aa10c6462f1d825143879be59e38?d=identicon&s=25 Charles Oliver Nutter (Guest)
on 2007-05-10 09:42
(Received via mailing list)
Bill Kelly wrote:
>> Could you tell us why you think it is "unsafe" ?
>
> Hi,
>
> I'm not sure if this is what MenTaLGuY meant, but one way that
> Thread#raise is unsafe, is that it can raise an exception in the
> specified thread while that thread is executing an 'ensure' block.

And to make it clear, we do implement kill, raise, and critical=, with
the following limitations:

- There are no guarantees all other threads will have stopped before
critical= allows the current thread to continue executing.
- Kill and raise require the target thread to eventually reach a
checkpoint where they are willing to "listen" to the kill or raise
event. If they don't, the calling thread will wait forever.

I even made these operations a bit cleaner and faster in 0.9.9, but
there's no way to do them perfectly with real concurrent threads.

- Charlie
F0afd024e17c0c4753aa8d618ba9bb0f?d=identicon&s=25 Marcin Raczkowski (Guest)
on 2007-05-10 11:46
(Received via mailing list)
On Wednesday 09 May 2007 19:20, Gary Wright wrote:
> One process can't inadvertently change the state of another.
> Windows programmers tend to reach for threads as a multi-tasking
> Gary Wright
As i mentioned earlier - easiest way to get REAL concurency (java VM
will NOT
use both processors - for few reasons JavaVM ALWAYS use one processor -
scalling for example Tomcat in production enviroment require running 2-4
java
VM's) is to use Slave gem - I'm using it for my project for concurent
parasing of logs - overhead on DRb is not big -and what's more you can
use it
on few machines if you want to scale it further

http://www.codeforpeople.com/lib/ruby/slave/slave-1.2.1/

creating new forks is really easy and you can create just one class for
procesing of data that can be concurent and everything else can be done
in
main program
912c61d9da47754de7039f4271334a9f?d=identicon&s=25 MenTaLguY (Guest)
on 2007-05-10 23:10
(Received via mailing list)
On Thu, 10 May 2007 15:40:57 +0900, Sylvain Joyeux
<sylvain.joyeux@polytechnique.org> wrote:
> Could you tell us why you think [Thread#raise] is "unsafe" ?

Because you have no control over when the exception is delivered, which
may be at the worst possible moment.  Even ensure does not provide
adequate protection.

Consider what happens with this code if an exception happens to arrive
just before the begin block is processed:

 @counter += 1
 begin
   # ... do stuff ...
 ensure
   @counter -= 1
 end

Lest you think there's an easy fix, consider what happens with this
second example if an exception arrives after the begin block is entered,
but before the counter has been incremented:

 begin
   @counter += 1
   # ... do stuff ...
 ensure
   @counter -= 1
 end

-mental
912c61d9da47754de7039f4271334a9f?d=identicon&s=25 MenTaLguY (Guest)
on 2007-05-10 23:15
(Received via mailing list)
On Thu, 10 May 2007 18:45:47 +0900, Marcin Raczkowski
<swistak@mailx.expro.pl> wrote:
> As i mentioned earlier - easiest way to get REAL concurency (java VM will
> NOT use both processors - for few reasons JavaVM ALWAYS use one processor -

Have you got evidence for this?  I do not believe it to be the case for
a
non-green-threaded JVM.

-mental
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2007-05-11 20:47
(Received via mailing list)
Bill Kelly wrote:
>> Could you tell us why you think it is "unsafe" ?
>
>
> Note that 'timeout' functions by creating a temporary new thread
> which sleeps for the duration, then raises an exception in the
> 'current' thread that invoked timeout.
>
> If the timeout raises its exception at an unlucky moment, the
> various internals of ConditionVariable#wait and Mutex#synchronize
> that depend on ensure blocks to restore their class invariants are
> skipped, resulting in nasty things like a permanently locked mutex.
>
> Not fun... :(

This is disturbing.

Is #timeout inherently unsafe, if it is implemented as a thread, even in
MRI ruby's green threads?

Ruby gives you a lot of freedom to do anything you want inside of ensure
clauses, and I guess this means that ensure clauses can't be given
special treatment--the ensure clause itself might be what needs to be
interrupted by the timeout. That seems to rule out treating ensure
clauses as a critical section, for example. And it seems to rule out a
method like Thread#raise_unless_in_ensure or
Thread#raise_after_ensure_finishes.

What if there were two kind of ensure clauses, one which is
uninterruptible (to be used only for cleanup that is deterministic) and
one which is interruptible (and not guaranteed to finish)?

What's the best practice in current MRI ruby? Use Timeout only in cases
where you know it is safe, and otherwise use #select timeouts or
whatever else is appropriate?
4feed660d3728526797edeb4f0467384?d=identicon&s=25 Bill Kelly (Guest)
on 2007-05-11 23:44
(Received via mailing list)
From: "Joel VanderWerf" <vjoel@path.berkeley.edu>
>
> Ruby gives you a lot of freedom to do anything you want inside of ensure
> clauses, and I guess this means that ensure clauses can't be given
> special treatment--the ensure clause itself might be what needs to be
> interrupted by the timeout. That seems to rule out treating ensure
> clauses as a critical section, for example.

Yeah... I agree in general.  However, . . .

> What if there were two kind of ensure clauses, one which is
> uninterruptible (to be used only for cleanup that is deterministic) and
> one which is interruptible (and not guaranteed to finish)?

I'd probably settle for a Thread#raise_asap (or #raise_safe, or
whatever.)  Because in theory, even though one *could* write
unfriendly code in an ensure block that took a long time to execute; in
practice all the ensure blocks I can recall seeing were doing what
appeared to be very simple, deterministic cleanup.

With that, it would be trivial to implement a Timeout#timeout_safe; and
I suspect it would be rare indeed when someone would need or want
to use the unsafe version...

> What's the best practice in current MRI ruby? Use Timeout only in cases
> where you know it is safe, and otherwise use #select timeouts or
> whatever else is appropriate?

That's pretty much my current practice.  I use Timeout sparingly, and am
extremely careful with it.


Regards,

Bill
912c61d9da47754de7039f4271334a9f?d=identicon&s=25 MenTaLguY (Guest)
on 2007-05-11 23:54
(Received via mailing list)
On Sat, 12 May 2007 03:46:58 +0900, Joel VanderWerf
<vjoel@path.berkeley.edu> wrote:
> This is disturbing.
>
> Is #timeout inherently unsafe, if it is implemented as a thread, even in
> MRI ruby's green threads?

Correct.  #timeout as presently implemented is NEVER safe to use.

> What if there were two kind of ensure clauses, one which is
> uninterruptible (to be used only for cleanup that is deterministic) and
> one which is interruptible (and not guaranteed to finish)?

Nope, that's still not sufficient.  The fundamental problem is that
other threads can _arbitrarily_ mess with control flow by injecting
exceptions via Thread#raise.  There's no way to guarantee invariants
will be preserved, no matter how clever your ensure implementation is.

-mental
912c61d9da47754de7039f4271334a9f?d=identicon&s=25 MenTaLguY (Guest)
on 2007-05-11 23:59
(Received via mailing list)
On Sat, 12 May 2007 06:43:39 +0900, "Bill Kelly" <billk@cts.com> wrote:
> I'd probably settle for a Thread#raise_asap (or #raise_safe, or
> whatever.)  Because in theory, even though one *could* write
> unfriendly code in an ensure block that took a long time to execute; in
> practice all the ensure blocks I can recall seeing were doing what
> appeared to be very simple, deterministic cleanup.

No, that's still not sufficient.  If an exception can be injected at an
arbitrary point by an external source, there's simply no way to write
sane code.

The only safe model for inter-thread communication is one where both
participants agree to communicate.  You'd need something like a
Thread#receive_exception that was explicitly called on the receiving
side -- of course, that's not too helpful for the purposes to which
Thread#raise is usually put.

The fundamental problem is really that most of Ruby's blocking
operations don't have allowance for timeout built into their API, which
is particularly sad since they're all built on top of select (in MRI,
anyway) and that would be really easy to do.  The whole #timeout thing
is an unsafe workaround which can never be made safe by its very nature.

-mental
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2007-05-12 00:08
(Received via mailing list)
MenTaLguY wrote:
...
>> What if there were two kind of ensure clauses, one which is
>> uninterruptible (to be used only for cleanup that is deterministic) and
>> one which is interruptible (and not guaranteed to finish)?
>
> Nope, that's still not sufficient.  The fundamental problem is that other threads can 
_arbitrarily_ mess with control flow by injecting exceptions via Thread#raise.  There's no 
way to guarantee invariants will be preserved, no matter how clever your ensure 
implementation is.

But what if we limit that arbitrary power by adding a new construct?

Suppose thread1 is executing this code:

   begin
   ensure_uninterruptible # not in ruby yet
     # quick and deterministic cleanup code
   end

and suppose that thread2 does this:

   thread1.raise

Can't we implement ensure_uninterruptible in such a way that
thread1.raise waits until thread1 finishes the clause (or maybe raises
an error in thread2 instead of in thread1)?

I'm not sure it's a good idea, but is there a reason it couldn't be done
with green threads?
4feed660d3728526797edeb4f0467384?d=identicon&s=25 Bill Kelly (Guest)
on 2007-05-12 00:48
(Received via mailing list)
From: "MenTaLguY" <mental@rydia.net>
>
> On Sat, 12 May 2007 06:43:39 +0900, "Bill Kelly" <billk@cts.com> wrote:
>> I'd probably settle for a Thread#raise_asap (or #raise_safe, or
>> whatever.)  Because in theory, even though one *could* write
>> unfriendly code in an ensure block that took a long time to execute; in
>> practice all the ensure blocks I can recall seeing were doing what
>> appeared to be very simple, deterministic cleanup.
>
> No, that's still not sufficient.  If an exception can be injected at an arbitrary
> point by an external source, there's simply no way to write sane code.

I thought what I was proposing was to _limit_ the current arbitrariness.

When I write code, I'm used to considering that any method call I make
may raise an exception.  (Including exceptions like NoMemoryError and
Interrupt.)

If we could prevent Thread#raise from happening within an ensure block,
and we could guarantee that an assignment to a variable would similarly
be non-interruptable (meaning, an exception can't be raised between
the point where a method call completes, and its result is assigned to
a variable) ... wouldn't that be getting us pretty close to being able
to
write "sane" code?

Or am I just missing out on something fundamental?  (If so, I'm most
definitely interested to learn.)


Regards,

Bill
912c61d9da47754de7039f4271334a9f?d=identicon&s=25 MenTaLguY (Guest)
on 2007-05-12 01:18
(Received via mailing list)
On Sat, 12 May 2007 07:47:57 +0900, "Bill Kelly" <billk@cts.com> wrote:
> If we could prevent Thread#raise from happening within an ensure block,
> and we could guarantee that an assignment to a variable would similarly
> be non-interruptable (meaning, an exception can't be raised between
> the point where a method call completes, and its result is assigned to
> a variable) ... wouldn't that be getting us pretty close to being able to
> write "sane" code?

Closer, but in this context "safe" is an all-or-nothing proposition.
Simply making variable assignments atomic falls far, far short of what's
needed.  What you're actually groping towards is atomic transactions --
the ability to take an arbitrary block of code and say "if this block
does not complete successfully, any of its effects should be rolled back
before propagating the exception".  Of course, not all effects (e.g. IO)
_can_ be rolled back, so you're still not entirely safe in that case.

> Or am I just missing out on something fundamental?  (If so, I'm most
> definitely interested to learn.)

Yes.  You have to be worried about all of the code involved (e.g. also
the arbitrarily complex implementations of any methods you call), not
just your own immediate code.

-mental
912c61d9da47754de7039f4271334a9f?d=identicon&s=25 MenTaLguY (Guest)
on 2007-05-12 01:26
(Received via mailing list)
On Sat, 12 May 2007 07:08:05 +0900, Joel VanderWerf
<vjoel@path.berkeley.edu> wrote:
> Can't we implement ensure_uninterruptible in such a way that
> thread1.raise waits until thread1 finishes the clause (or maybe raises
> an error in thread2 instead of in thread1)?

Sure.  But it's still not enough -- you'll notice that the examples I
gave earlier were concerned with race conditions around entry of the
protected section itself, not even the ensure clause.

What you actually need to do is make uninterruptability the universal
default; interruptability at a specific point must be specifically
allowed for.

-mental
912c61d9da47754de7039f4271334a9f?d=identicon&s=25 MenTaLguY (Guest)
on 2007-05-12 01:39
(Received via mailing list)
On Sat, 12 May 2007 08:25:28 +0900, MenTaLguY <mental@rydia.net> wrote:
> What you actually need to do is make uninterruptability the universal
> default; interruptability at a specific point must be specifically allowed
> for.

Another way to do this is to work in terms of atomic transactions (e.g.
STM, if your STM implementation is itself safe in the face of
asynchronous exceptions).

-mental
4feed660d3728526797edeb4f0467384?d=identicon&s=25 Bill Kelly (Guest)
on 2007-05-12 01:41
(Received via mailing list)
From: "MenTaLguY" <mental@rydia.net>
>
>> Or am I just missing out on something fundamental?  (If so, I'm most
>> definitely interested to learn.)
>
> Yes.  You have to be worried about all of the code involved (e.g. also the
> arbitrarily complex implementations of any methods you call), not just your
> own immediate code.

Oh.  That's different.

I was just looking for whether we could arrive at constraints that would
allow a given routine to be written in a way that 100% safely handled
these new hypothetical Thread#raise semantics.

If I happen to be calling other routines that aren't written to handle
exceptions safely, well, yeah, that sucks for me.

But if one method can be written to be safe, why can't they all?  Why,
then,
would I have to worry about anything other than my own immediate code,
unless I am assuming the code I'm calling is broken WRT exception
handling, in which case... well, it's broken.  But that's different.

?

Regards,

Bill
912c61d9da47754de7039f4271334a9f?d=identicon&s=25 MenTaLguY (Guest)
on 2007-05-12 02:02
(Received via mailing list)
On Sat, 12 May 2007 08:40:43 +0900, "Bill Kelly" <billk@cts.com> wrote:
> If I happen to be calling other routines that aren't written to handle
> exceptions safely, well, yeah, that sucks for me.

That goes for most of core and stdlib, though.  At least in the face of
_asynchronous_ exceptions.  Have a look at Set#replace, for instance.

> But if one method can be written to be safe,

I'm not sure any non-trivial method can be.  Additionally, if we're
dealing with a non-green-threaded case where an exception can be
delivered
at any time (not just set scheduling points), it's really not possible
at all.

Rather than my continuing to make bald assertions, though, if you'd like
to provide a code sample I can probably illustrate what I mean.

-mental
4feed660d3728526797edeb4f0467384?d=identicon&s=25 Bill Kelly (Guest)
on 2007-05-13 10:50
(Received via mailing list)
From: "MenTaLguY" <mental@rydia.net>
>
> Rather than my continuing to make bald assertions, though, if you'd like
> to provide a code sample I can probably illustrate what I mean.

Thanks,

Mainly this has happened when I wanted to do some sort of
timed-wait on a condition variable.

I've seen this concept reccur as recently as this week...
Obviously if Ruby had the concept of timing out on a
mutex or cond-var wait...

But I'm sorry, I've gotten ahead of myself.  I think, if we
could just ...... sort of,  <3


Er, e hehe

Well my conceptualization was something along the lines
of what boost::shared_ptr does in C++; that is: there are
certain language semantics that are _guaranteed_....

Smart-ptrs only work in C++ because of language-given
semantics that describe exactly what will happen on an
assignment following a function call, and dtors called
when a function exits, etc.

My feeling was, ensure blocks in ruby, could be similarly
described, such that, one could _guarantee_ certain
semantics .... similar to what's guaranteed in C++ that
makes wrapped ptrs be 100% reliable as smart-ptrs.

RUBY NEEDS SMART PTR SEMANTICS

is a concept

worth-while?

:D

Just a thought,

Regards,

Bill
4feed660d3728526797edeb4f0467384?d=identicon&s=25 Bill Kelly (Guest)
on 2007-05-13 19:36
(Received via mailing list)
From: "Bill Kelly" <billk@cts.com>
>
> RUBY NEEDS SMART PTR SEMANTICS

Ugh, sorry for the noise.

I was having a weird day yesterday.
Ede2aa10c6462f1d825143879be59e38?d=identicon&s=25 Charles Oliver Nutter (Guest)
on 2007-05-15 03:04
(Received via mailing list)
MenTaLguY wrote:
> On Thu, 10 May 2007 18:45:47 +0900, Marcin Raczkowski <swistak@mailx.expro.pl> wrote:
>> As i mentioned earlier - easiest way to get REAL concurency (java VM will
>> NOT use both processors - for few reasons JavaVM ALWAYS use one processor -
>
> Have you got evidence for this?  I do not believe it to be the case for a
> non-green-threaded JVM.

The OP is incorrect. Java VMs always use all cores in the system, except
in a very few specialized VMs that are green threaded.

Even if we're talking about only one thread of execution, there's still
the GC thread which generally runs in parallel.

- Charlie
934180817a3765d132193a5428f99051?d=identicon&s=25 Sylvain Joyeux (Guest)
on 2007-06-04 18:04
(Received via mailing list)
> - Kill and raise require the target thread to eventually reach a
> checkpoint where they are willing to "listen" to the kill or raise
> event. If they don't, the calling thread will wait forever.
I think this is fair. I also think that the core developer may need to
really think about what should be a checkpoint *in the language itself*
(for instance, end of a block, end of a method, whatever). For instance,
not allowing to have a checkpoint in an "ensure" context would fix the
ensure-related issues (but may not fix others that I don't see)

My main use of Thread#raise is "returning" from a
ConditionVariable#wait.
Can I assume this is seen as a checkpoint by JRuby ?

Sylvain Joyeux
This topic is locked and can not be replied to.