この答えのために私は次のようなコードを書きました:
def show_wait_spinner
dirty = false
spinner = Thread.new{
loop{
print "*"
dirty = true
sleep 0.1
print "\b"
dirty = false
}
}
yield
spinner.kill
print "\b" if dirty
end
print "A"
show_wait_spinner{ sleep rand }
puts "B"
目標は、最終出力がスレッドによってまだ印刷されていない場合に最終出力"AB"
を印刷することを確認することです。"\b"
そのコードは、存在するRubyでは厄介に思えbegin/rescue/ensure
ます。そこで、他のいくつかの実装を試しましたshow_wait_spinner
。"AB"
それらのすべては、それが常に出力であり、決して"A*B"
またはではないことを保証できません"AB*"
。
このロジックを実装するためのよりクリーンでRuby風の方法はありますか?
Mutexを介してループの終わりで停止します
def show_wait_spinner
stop = false
stopm = Mutex.new
spinner = Thread.new{
loop{
print "*"
sleep 0.1
print "\b"
stopm.synchronize{ break if stop }
}
}
yield
stopm.synchronize{ stop = true }
STDOUT.flush
end
…しかし、これは常に「A * B」になるので、私のロジックはオフでなければなりません。
スレッドローカル変数を介してループの終わりで停止します
この2回目の試行では、「A * B」が印刷されることもあれば、「AB」が印刷されることもあります。
def show_wait_spinner
stop = false
spinner = Thread.new{
Thread.current[:stop] = false
loop{
print "*"
sleep 0.1
print "\b"
stopm.synchronize{ break if Thread.current[:stop] }
}
}
yield
spinner[:stop] = true
STDOUT.flush
end
スレッドを強制終了して確認します
def show_wait_spinner
spinner = Thread.new{
dirty = false
begin
loop{
print "*"
dirty = true
sleep 0.1
print "\b"
dirty = false
}
ensure
print "\b" if dirty
end
}
yield
spinner.kill
STDOUT.flush
end
スレッドを上げて救助する
def show_wait_spinner
spinner = Thread.new{
dirty = false
begin
loop{
print "*"
dirty = true
sleep 0.1
print "\b"
dirty = false
}
rescue
puts "YAY"
print "\b" if dirty
end
}
yield
spinner.raise
STDOUT.flush
end