< :前の番号
^ :番号順リスト
> :次の番号
P :前の記事(スレッド移動)
N :次の記事(スレッド移動)
|<:前のスレッド
>|:次のスレッド
^ :返事先
_:自分への返事
>:同じ返事先を持つ記事(前)
<:同じ返事先を持つ記事(後)
---:分割してスレッド表示、再表示
| :分割して(縦)スレッド表示、再表示
~ :スレッドのフレーム消去
.:インデックス
..:インデックスのインデックス
Issue #17221 has been updated by shan (Shannon Skipper).
It seems like both "a" and "the" work here. I might say, "cannot transfer to a yielding Fiber" or "attempted transfer to a yielding Fiber."
----------------------------------------
Bug #17221: Relax the Fiber#transfer's limitation
https://bugs.ruby-lang.org/issues/17221#change-88001
* Author: ko1 (Koichi Sasada)
* Status: Closed
* Priority: Normal
* Backport: 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN
----------------------------------------
Using `Fiber#transfer` with `Fiber#resume` for a same Fiber is limited (once `Fiber#transfer` is called for a fiber, the fiber can not be resumed more).
```ruby
require 'fiber'
f1 = nil
f2 = Fiber.new{
f1.transfer
}
f1 = Fiber.new{
f2.transfer
Fiber.yield 10
Fiber.yield 20
}
p f1.resume #=> 10
p f1.resume #=> `resume': cannot resume transferred Fiber (FiberError)
```
This restriction was introduced to protect the resume/yield chain, but we realized 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 = Fiber.current
f1 = f2 = nil
f1 = Fiber.new{
f2 = Fiber.new{
root.transfer(10)
}
f2.resume
}
p f1.transfer #=> 10
# root <-----+
# | |
# v | transfer
# f1 -> f2 -+ # resume/yield chain
# horizontal direction: resume
# vertical direction: transfer
p f1.transfer #=> 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 = f2 = nil
f1 = Fiber.new{
f2 = Fiber.new{
Fiber.yield
}
f2.resume
10
}
p f1.transfer #=> 10
# root
# | ^
# | | transfer
# v |
# f1 --> f2 # resume/yield chain
# <--
p f2.transfer #=> `transfer': attempt to transfer to an yielding fiber (FiberError)
# 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 = f2 = nil
f2 = Fiber.new{
f1.resume #=> attempt to resume the transferring fiber (FiberError)
}
f1 = 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 = Fiber.new do
Fiber.yield #=> `yield': attempt to yield on not resumed fiber (FiberError)
end
f1 = 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 = nil
f2 = Fiber.new{
f1.transfer
}
f1 = Fiber.new{
f2.transfer
Fiber.yield 10
Fiber.yield 20
}
p f1.resume #=> 10
p f1.resume #=> 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 chain 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 another fiber), this behavior also breaks the resume/yield chain.
So at the end of a transferred fiber, switch to the edge of resume chain from 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 = Fiber.new{
10
}
f2 = Fiber.new{
f3.transfer + 20
}
f1 = Fiber.new{
f2.resume
}
p f1.resume #=> 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=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>