[ruby-list:50593] Re: Fwd: Re: Re: [質問]thread内sleepコール 他threadよりsleep状態からrun状態にされた際、指定時間sleepさせるには?
From:
<yamataka@...08.itscom.net>
Date:
2017-10-04 07:18:03 UTC
List:
ruby-list #50593
> こんにちは、市田です。
市田さん
山口です。
いつもご教示ありがとうございます。
> On 2017/09/29 19:38, yamataka@u08.itscom.net wrote:
>> 但し、exec_thread 再開後は、停止した際から、sleep設定時間の残り時間を
>> exec_threadは実行というような感じにしたいのです。
>スレッドが stop から run に状態変化する際、sleep の途中からというのは
>ないのではと思います。
そうでしたか。
> exec_thread = Thread.new do
> loop do
> puts "in exec_thread"
> n = 10 # sleep 100s
> puts "in exec_thread sleep start #{n}s"
> start = Time.now
> while n > 0
> sleep(0.1)
> n -= 0.1
> end
> puts "in exec_thread sleep end %.1f" % (Time.now - start)
> end
>end
サンプルコード提示ありがとうございます。
>「刻み」をどうするかは、どれくらい sleep するのかと、期待する時間精度
> によって変わるでしょう。
時間精度は、厳密に正確でなくて困らず
> また、元々のsleep時間以上、停止させられていた場合でも、「継続」するの
> が良いかどうかは考慮要と思います。
継続するというような感じて、結局、input_thread から Queue を用いて、
exec_thread 側で、その命令に従って動くようなコードにしました。
exec_threadでは、sleepシステムコール待ち時間全て指定するのではなく1s単位
で実行、その回数を管理。
その実行中に、input_threadより、pause 命令がくると、sleep実行を行わない。
再度、pause命令がきたら、残りの sleep(1) の回数を実行する。
というような以下の様なコードになりました。
# もっとこう書いた方が、ruby らしいとかあれば、コメント頂けると幸いです。
require 'pp'
q = Queue.new
def exec_run
puts "[INFO] #{__method__} start"
end
def exec_pause
puts "[INFO] #{__method__} pause"
end
def exec_nil
puts "[INFO] #{__method__} do nothing"
end
exec_thread = Thread.new do
# sd: state diagram
sd = [
# ets etc call
[{:run => :pause}, :exec_pause],
[{:run => :run }, :exec_nil],
[{:pause => :pause}, :exec_nil],
[{:pause => :run }, :exec_run]
]
puts "in exec_thread"
ets = :run # ets: exec thread status
sc = 30 # sleep count
rseq = :run1 # rseq: run sequence
loop do
begin
etc = q.pop(non_block = true) # etc : exec thread control
func = nil
sd.each do |sdc|
f = false
match = sdc.first.select { |k,v| k == ets && v == etc }
unless match.empty?
ets = match.to_a.first[1]
func = sdc[1]
f = true
end
break if f
end
self.send(func)
rescue => e
case ets
when :run
case rseq
when :run1
puts "start run1"
rseq = :runs
when :runs
sc = 20
rseq = :runsc
when :runsc
puts "sleep #{sc}s"
sleep(1)
sc -= 1
rseq = :run1 if sc < 0
else
puts "[ERROR] #{rseq}"
exit
end
when :pause
else # do nothing
end
end
end
end
input_thread = Thread.new do
ets = :run # ets: execute thread status
loop do
ret = STDIN.gets
case ret
when /^ *q *$/
puts "get q"
exit
when /^ *p *$/
puts "get p"
if ets == :run
ets = :pause
q.push(:pause)
else
ets = :run
q.push(:run)
end
end
end
end
exec_thread.join
input_thread.join