Project

General

Profile

Feature #5788

Thread#at_exit

Added by Masaki Matsushita over 4 years ago. Updated almost 4 years ago.

Status:
Feedback
Priority:
Normal
Assignee:
-
[ruby-core:41774]

Description

=begin
I propose a new method Thread#at_exit.
It is to register a block which will be called when the thread ends.

p Thread.main #=> #
p t = Thread.new{ # do something } #=> #
t.at_exit{ p Thread.current }
t.join #=> #

Thread.main.at_exit is equal to Kernel.at_exit.

I think this method is useful for waiting plural running threads end.

Without Thread#at_exit:
t1 = Thread.new{ sleep 1 }
t2 = Thread.new{ sleep 2 }

[t1, t2].each do |t|
Thread.new do
t.join
puts "Thread ended!"
end
end

[t1, t2].each(&:join)

To handle threads' end immediately, the same number of threads as ones to wait is needed.

For example, Ruby's standard library thwait.rb does so.

With Thread#at_exit:
t1 = Thread.new{ sleep 1 }
t2 = Thread.new{ sleep 2 }

[t1, t2].each do |t|
# It runs when interpreter ends.
t.at_exit{ puts "Thread ended!" }
end

New threads are not necessary.

I made a patch.
Patched ruby passes test-all.
=end

patch.diff View (2.13 KB) Masaki Matsushita, 12/22/2011 05:35 PM

patch2.diff View (2.41 KB) Masaki Matsushita, 12/25/2011 12:42 AM

patch3.diff View (3.26 KB) Masaki Matsushita, 02/01/2012 10:58 PM

History

#1 [ruby-core:41785] Updated by Nobuyoshi Nakada over 4 years ago

  • Status changed from Open to Feedback

=begin
Just reviewed briefly.
* (({th->at_exit})) needs to be marked,
* (({th->at_exit})) should be hidden, and
* a hook registered to the main thread seems to be executed in a child
process forked in a sub-thread too.

Second, what will happen if the thread has terminated already? Also,
it might be useful if the thread or its value is passed to the hook.
=end

#2 [ruby-core:41793] Updated by sorah Shota Fukumori over 4 years ago

i don't think the name of this method is good… are there any more suitable name for this method?

#3 [ruby-core:41796] Updated by Motohiro KOSAKI over 4 years ago

I don't think ruby impl w/o GVL can implement this feature.

#4 [ruby-core:41798] Updated by Masaki Matsushita over 4 years ago

=begin
Nakada-san, thank you for your reviewing.
I improved the patch at some points.
* th->at_exit is to be marked.
* If the thread is dead, Thread#at_exit returns nil.
* The thread is passed to the hooks(including hooks on main thread).
* Registered hooks are executed in reverse order of registration(same as END or Kernel.at_exit).
=end

#5 [ruby-core:41823] Updated by Nobuyoshi Nakada over 4 years ago

=begin
Calling (({rb_gc_mark()})) only once at the hook definition makes no sense.
You have to mark it in (({rb_thread_mark()})).
=end

#6 [ruby-core:41826] Updated by Eric Wong over 4 years ago

Motohiro KOSAKI kosaki.motohiro@gmail.com wrote:

I don't think ruby impl w/o GVL can implement this feature.

pthread_key_create() can be used to register a destructor function.
I don't know about other thread APIs, though.

#7 [ruby-core:41827] Updated by Motohiro KOSAKI over 4 years ago

2011/12/27 Eric Wong normalperson@yhbt.net:

Motohiro KOSAKI kosaki.motohiro@gmail.com wrote:

I don't think ruby impl w/o GVL can implement this feature.

pthread_key_create() can be used to register a destructor function.
I don't know about other thread APIs, though.

No.
The proposal API can replace with another thread's exiting hook. It's
racy be definition.
pthread_key_create() can't help.

Moreover, the proposal syntax may accelerate careless racy code.
That's bad. We sould
only encourage good custom.

#8 [ruby-core:42309] Updated by Masaki Matsushita over 4 years ago

=begin
I modified the patch.
* use mutex on define_at_exit to avoid race.
* mark th->at_exit and th->at_exit_lock in rb_thread_mark().
=end

#9 [ruby-core:49686] Updated by Yusuke Endoh almost 4 years ago

  • Target version set to next minor

Also available in: Atom PDF