質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.03%

  • Ruby

    6352questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby thread内sleepコール実行中 threadそのものを停止させたい

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 139

roswell

score 0

yama@roswell:~$ uname -a  
CYGWIN_NT-6.3 JPC20165182 2.6.0(0.304/5/3) 2016-08-31 14:32 x86_64 Cygwin  
yama@roswell:~$ ruby --version ruby 2.2.5p319 (2016-04-26 revision 54774) [x86_64-cygwin]  
の環境で、  

2つのthread  
input_thread,exec_thread  
を用いて、  

input_threadにて、標準入力より p がタイプされると、  
exec_thread を thread.sleep で、sleep状態にしています。  
(下記コードの (*1) の部分)  

exec_thread 内で、sleepコールで、既にsleep状態になっている場合  
(下記コードの(*2)の部分)  
sleepコールで、指定した時間が来れば、run状態になりますが...  

exec_threadそのものの動きを止めたい、すなわちsleepコールの動きのそのもの  
を止めたい場合は、  
どうすればよいのかご教示いただけますでしょうか?  

簡単に説明すると、  
input_thread で、標準入力より p がタイプされると、exec_thread を停止。  
また、p がタイプされると、exec_thread 再開。  
但し、exec_thread 再開後は、停止した際から、sleep設定時間の残り時間を  
exec_threadは実行というような感じにしたいのです。 

exec_thread = Thread.new do
   loop do
       puts "in exec_thread"   
       n = 30 # sleep specified secs  
       puts "in exec_thread sleep start #{n}s"  
       sleep(n) # (*2)   
       puts "in exec_thread sleep end"  
    end  
end  

input_thread = Thread.new do
 loop do  
   ret = STDIN.gets  

   case ret  
   when /^ *q *$/  
     puts "get q"  
     exit  
   when /^ *p *$/     
     puts "get p" # (*1)  
     exec_thread.stop
   end  
 end  
end 

exec_thread.join  
input_thread.join  

 

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

0

1秒(あるいはそれ以下)ずつsleepするようにして、自分で残り待ち時間をカウントダウンするしかないと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/02 13:12

    otn さん、回答ありがとうございます。

    > 自分で残り待ち時間をカウントダウンするしかない

    の "自分で" というのは、"exec_thread で" ということでしょうか?

    キャンセル

  • 2017/10/02 13:21

    はい。sleepしたいthreadでという意味です。

    キャンセル

  • 2017/10/02 18:11

    otn さん

    > 自分で残り時間をカウントする...

    下記の様にコード変更してみましたが...、他 thread から stop を call しても、
    結局 sleep している箇所自体は動く訳で、望んだ動作にはならないようなのですが
    何か勘違いしていますでしょうか?

    exec_thread をこのように改変すれば良い等の具体例を、もしよろしければご教示いただけないでしょうか?

    ■最初にいただいたアドバイスの様に自分でカウントダウンするようにした? コード
    exec_thread = Thread.new do
    loop do
    puts "in exec_thread"

    n = 30 # sleep specified secs
    puts "in exec_thread sleep start #{n}s"

    while n > 0 do
    sleep(1)
    n -= 1
    end

    puts "in exec_thread sleep end"
    end
    end

    キャンセル

0

otn さんのアドバイスを元に、下記のような自己解決に至りました。
もっとこうした方が良い等のアドバイス有れば、ご教示ください。

q = Queue.new

exec_thread = Thread.new do
  puts "in exec_thread"

  ets = :run # ets: exec thread status

  loop do

    n = 30 # sleep specified secs
    puts "in exec_thread sleep start #{n}s"

    loop do
      begin
        etc = q.pop(non_block = true) # etc : exec thread control

        case ets
        when :run
          if etc == :stop
            puts "in exec_thread goes to sleep stop mode"
            ets = :stop
          end
        when :stop
          if etc == :run
            puts "in exec_thread goes to sleep run mode"
            ets = :run
          end
        end
      rescue => e
        case ets
        when :run
          puts "sleep count down #{n}"
          sleep(1)
          n -= 1
          break if n < 0
        when :stop
        else # do nothing
        end
      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 = :stop
        q.push(:stop)
      else
        ets = :run
        q.push(:run)
      end
    end
  end
end

exec_thread.join
input_thread.join

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 91.03%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Ruby

    6352questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。