< :前の番号
^ :番号順リスト
> :次の番号
P :前の記事(スレッド移動)
N :次の記事(スレッド移動)
|<:前のスレッド
>|:次のスレッド
^ :返事先
_:自分への返事
>:同じ返事先を持つ記事(前)
<:同じ返事先を持つ記事(後)
---:分割してスレッド表示、再表示
| :分割して(縦)スレッド表示、再表示
~ :スレッドのフレーム消去
.:インデックス
..:インデックスのインデックス
Issue #17221 has been updated by duerst (Martin D=FCrst).
Eregon (Benoit Daloze) wrote in #note-11:
> I believe it's `a yielding Fiber` (the first sound in yield-ing is not a =
vowel sound)
A Yes indeed for this question. (not an yes :-)
----------------------------------------
Bug #17221: Relax the Fiber#transfer's limitation
https://bugs.ruby-lang.org/issues/17221#change-87975
* Author: ko1 (Koichi Sasada)
* Status: Open
* Priority: Normal
* Backport: 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN
----------------------------------------
Using `Fiber#transfer` with `Fiber#resume` for a same Fiber is limited (onc=
e `Fiber#transfer` is called for a fiber, the fiber can not be resumed more=
).
```ruby
require 'fiber'
f1 =3D nil
f2 =3D Fiber.new{
f1.transfer
}
f1 =3D Fiber.new{
f2.transfer
Fiber.yield 10
Fiber.yield 20
}
p f1.resume #=3D> 10
p f1.resume #=3D> `resume': cannot resume transferred Fiber (FiberError)
```
This restriction was introduced to protect the resume/yield chain, but we r=
ealized that it is too much to protect the chain.
Instead of the current restriction, we introduce some other protections.
(1) can not transfer to the resuming fiber.
```ruby
require 'fiber'
root =3D Fiber.current
f1 =3D f2 =3D nil
f1 =3D Fiber.new{
f2 =3D Fiber.new{
root.transfer(10)
}
f2.resume
}
p f1.transfer #=3D> 10
# root <-----+
# | |
# v | transfer
# f1 -> f2 -+ # resume/yield chain
# horizontal direction: resume
# vertical direction: transfer
p f1.transfer #=3D> attempt to transfer to a resuming fiber (FiberError)
# f1 has it's own resume/yield chain, and f1.transfer breaks the chain
# root <-----+
# || (error)|
# vv |
# f1 -> f2 -+ # resume/yield chain
```
(2) can not transfer to the yielding fiber.
```ruby
require 'fiber'
f1 =3D f2 =3D nil
f1 =3D Fiber.new{
f2 =3D Fiber.new{
Fiber.yield
}
f2.resume
10
}
p f1.transfer #=3D> 10
# root =
# | ^
# | | transfer
# v |
# f1 --> f2 # resume/yield chain
# <--
p f2.transfer #=3D> `transfer': attempt to transfer to an yielding fiber (F=
iberError)
# f2 is waiting for the resume, so the transfer is not allowed.
# root --+
# | ^ | transfer (error)
# | | |
# v | v
# f1 --> f2 # resume/yield chain
# <--
```
(3) can not resume transferring fiber.
```ruby
require 'fiber'
f1 =3D f2 =3D nil
f2 =3D Fiber.new{
f1.resume #=3D> attempt to resume the transferring fiber (FiberError)
}
f1 =3D Fiber.new{
f2.transfer
}
f1.transfer
# root
# |
# v
# f1 <-+
# | |
# v | resume (error)
# f2 --+
# f1 seems waiting for transfer from other fibers.
```
(4) can not yield from not-resumed fiber
```
require 'fiber'
f2 =3D Fiber.new do
Fiber.yield #=3D> `yield': attempt to yield on not resumed fiber (FiberEr=
ror)
end
f1 =3D Fiber.new
f2.transfer
end
p f1.transfer
# root
# |
# v
# f1
# |
# v
# <- f2
# yield to where ...? (2.7 switches to root fiber)
```
and remove current restriction. The first example works fine:
```ruby
require 'fiber'
f1 =3D nil
f2 =3D Fiber.new{
f1.transfer
}
f1 =3D Fiber.new{
f2.transfer
Fiber.yield 10
Fiber.yield 20
}
p f1.resume #=3D> 10
p f1.resume #=3D> 20
# root -> f1 <-+
# | |
# v |
# f2 --+
```
The basic idea is respect *programmer's intention*.
For (1), resuming fiber should be switched by the `Fiber.yield`.
For (2), yielding fiber should be switched by the `Fiber#resume`.
For (3), transferring fiber should be switched by the `Fiber#transfer`.
Mainly (1) can keep the resume/yield chain. Also (2) and (3) makes the chai=
n and relationships with fibers cleanly.
----
Also at the end of a transferred fiber, it had continued on root fiber.
However, if the root fiber resumed a fiber (and that fiber can resumed anot=
her fiber), this behavior also breaks the resume/yield chain.
So at the end of a transferred fiber, switch to the edge of resume chain fr=
om root fiber.
For example, root fiber resumed f1 and f1 resumed f2, transferred to f3 and=
f3 terminated, then continue from the fiber f2 (it was continued
from root fiber without this patch).
```ruby
require 'fiber'
f3 =3D Fiber.new{
10
}
f2 =3D Fiber.new{
f3.transfer + 20
}
f1 =3D Fiber.new{
f2.resume
}
p f1.resume #=3D> 30
# without this patch:
#
# root -> f1 -> f2
# ^ |
# | exit v
# +----------- f3
# with this patch:
#
# root -> f1 -> f2 <-+ # keep resume/yield chain
# | |
# v |
# f3 --+ exit
```
The patch is: https://github.com/ruby/ruby/pull/3636
---Files--------------------------------
clipboard-202010080257-u2lbv.png (25.5 KB)
-- =
https://bugs.ruby-lang.org/
Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=3Dunsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>