Feature #5788

Thread#at_exit

Added by Masaki Matsushita over 2 years ago. Updated over 1 year ago.

[ruby-core:41774]
Status:Feedback
Priority:Normal
Assignee:-
Category:core
Target version:next minor

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.atexit is equal to Kernel.atexit.

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 Magnifier (2.13 KB) Masaki Matsushita, 12/22/2011 05:35 PM

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

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

History

#1 Updated by Nobuyoshi Nakada over 2 years ago

  • Status changed from Open to Feedback

=begin
Just reviewed briefly.
* (({th->atexit})) 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 Updated by Shota Fukumori over 2 years ago

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

#3 Updated by Motohiro KOSAKI over 2 years ago

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

#4 Updated by Masaki Matsushita over 2 years ago

=begin
Nakada-san, thank you for your reviewing.
I improved the patch at some points.
* th->atexit 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 Updated by Nobuyoshi Nakada over 2 years ago

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

#6 Updated by Eric Wong over 2 years ago

Motohiro KOSAKI kosaki.motohiro@gmail.com wrote:

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

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

#7 Updated by Motohiro KOSAKI over 2 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.

pthreadkeycreate() 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.
pthreadkeycreate() can't help.

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

#8 Updated by Masaki Matsushita about 2 years ago

=begin
I modified the patch.
* use mutex on defineatexit to avoid race.
* mark th->atexit and th->atexitlock in rbthread_mark().
=end

#9 Updated by Yusuke Endoh over 1 year ago

  • Target version set to next minor

Also available in: Atom PDF