トップ 追記   RSS 1.0 FEED  

Journal InTime


2018-12-05 (Wed) [長年日記]

_ 特殊変数のスコープ

(この記事はRuby Advent Calendar 2018の参加記事です。)

Rubyはシンプルな文法が特長である。

Rubyには特殊変数と呼ばれる変数があって、見た目はグローバル変数だが、$_$& などの一部の変数はローカル変数に似たスコープを持っている。「似た」というのは厳密には違いがあって、基本的にブロックローカルではなくメソッドローカルなのだが、スレッドのブロックではスレッド毎に固有の値を持つ。

t = Thread.start {
  Thread.current.name = "sub"
  $_ = "foo"
  5.times do
    puts "#{Thread.current.name}: #$_" #=> 5回とも「sub: foo」と出力
    sleep(0.1)
  end
}
Thread.current.name = "main"
$_ = "bar"
5.times do
  puts "#{Thread.current.name}: #$_" #=> 5回とも「main: bar」と出力
  sleep(0.1)
end
t.join

この挙動は、単純にメソッドローカルにするとスレッドセーフでなくなってしまうからである。 では、以下のように同じProcオブジェクトを別々のスレッドで実行するとどうなるか?

def with_special_var(x, &block)
  Thread.current[:x] = x
  block.binding.eval("$_ = Thread.current[:x]")
  block.call
end

f = -> {
  5.times do
    puts "#{Thread.current.name}: #$_"
    sleep(0.1)
  end
}
t = Thread.start {
  Thread.current.name = "sub"
  with_special_var("foo", &f)
}
Thread.current.name = "main"
with_special_var("bar", &f)
t.join

実は処理系によって挙動が異なる。

CRubyの場合:

$ ruby -v t.rb                          
ruby 2.6.0dev (2018-11-28 trunk 66060) [x86_64-linux]
main: bar
sub: foo
main: bar
sub: foo
main: bar
sub: foo
main: bar
sub: foo
main: bar
sub: foo

JRubyの場合:

$ jruby -v t.rb
jruby 9.2.0.0 (2.5.0) 2018-05-24 81156a8 OpenJDK 64-Bit Server VM 9-Debian+0-9b181-4bpo91 on 9-Debian+0-9b181-4bpo91 +jit [linux-x86_64]
main: foo
sub: foo
main: foo
sub: foo
main: foo
sub: foo
main: foo
sub: foo
main: foo
sub: foo

JRubyでは両方のスレッドでProcオブジェクトを生成した環境の $_ が共有されるが、CRubyの場合はProcオブジェクトを生成した環境とスレッドを生成した環境が同一のメソッド呼び出し(上記の例ではトップレベル)だった場合、 $_ は各スレッド毎に別々の値を持つ。

CRubyでは特殊変数へのアクセスは以下のように実装されている。

static inline struct vm_svar *
lep_svar(const rb_execution_context_t *ec, const VALUE *lep)
{
    VALUE svar;

    if (lep && (ec == NULL || ec->root_lep != lep)) {
        svar = lep[VM_ENV_DATA_INDEX_ME_CREF];
    }
    else {
        svar = ec->root_svar;
    }

    VM_ASSERT(svar == Qfalse || vm_svar_valid_p(svar));

    return (struct vm_svar *)svar;
}

lep はlocal environment pointerでメソッドローカル変数が格納されている領域を指す。 ec->root_lep は各スレッドの実行環境のトップレベルのメソッドローカル変数が格納されている領域を指す。 両者が同じ値の場合、各スレッドのトップレベルの特殊変数を格納する ec->root_svar を返している。

JRubyの実装は読んでいないが、おそらく上記のように特殊変数のアクセス時に動的なチェックを行うのではなく、スレッド生成時にブロックが直接記述されている場合だけを特別扱いしているのだろう。

以下のようにProcオブジェクトとスレッドを別の環境で生成した場合は、CRubyでもJRubyと同じようにスレッド間で $_ の値が共有される。

def with_special_var(x, &block)
  Thread.current[:x] = x
  block.binding.eval("$_ = Thread.current[:x]")
  block.call
end

def make_proc
  -> {
    5.times do
      puts "#{Thread.current.name}: #$_"
      sleep(0.1)
    end
  }
end

f = make_proc
t = Thread.start {
  Thread.current.name = "sub"
  with_special_var("foo", &f)
}
Thread.current.name = "main"
with_special_var("bar", &f)
t.join

Rubyはシンプルな文法が特長である。

Tags: Ruby

2018-11-17 (Sat) [長年日記]

_ スタッドレスタイヤ交換

photo

イエローハットで聞いてみたらタイヤ代だけで10万円以上で工賃別と言われたので、楽天(タイヤホイール激安王国といういかにもな名前の店舗)でスタッドレスタイヤとタイヤ交換チケットを購入してみた。

取付店に直接送ってくれるけど、取付店は選べずに勝手に近くの店を指定されるという仕組みで、希望日時も備考欄に記入しないといけないのでちょっと面倒くさい。自分の場合は、たまたま近くに提携店舗が一つしかなく、希望日時通りに予約できたからよかったけど。

タイヤ自体は無難にヨコハマのIG50 PLUS(205/60R16)にして56,800円(税込)。一つ前のモデルだけど、交換前のIG30でも特に不満はなかったし、商品ページに2018年製造と明記されていて実際届いたものも4本とも2018年35週製造だった。

タイヤ交換(組み換え)チケットは1本1900円(税別)で、廃タイヤの引き取り料を別途店舗に直接1200円ちょっと支払った。 引き取り料はこちらから言わなかったら取られなさそうな感じだったので、まだあまり利用者がいないのかもしれない。


2018-10-15 (Mon) [長年日記]

_ バッテリー交換

photo

最近250DUKEの始動時にセルが少し頼りない気がしてバッテリーをチェックしたら電圧が11Vしかなかったので、バッテリーを交換した。

台湾ユアサのYTX-9BSに交換している人が多いようだが、Amazonの商品ページには「傾斜搭載でのバッテリー取付は不可」と書いてあって、250DUKEはかなり傾斜して搭載しないといけないのでNBCのGEL 9-BSにしてみた。 ゲルタイプのバッテリーははじめてだけど、どれくらいもつかな。

NBC [ エヌビーシー ] シールド型 バイク用バッテリー [ GELタイプ ] [ 液入充電済 ] GEL 9-BS

Tags: 250DUKE

2018-09-15 (Sat) [長年日記]

_ VORGUEフロントアクスルスペーサー

photo

とりあえずフロントの異音は収まったものの、フロントディスクとキャリパーの隙間があまりにも狭いのが気になって、VORGUEのフロントアクスルスペーサーを取り寄せてもらった。

センターが出たおかげかカシマコートのおかげかフロントの回転が軽くなったような気がする。

これでパーツ代10000円は痛いけど、店先に並んでた390/250DUKE(2016年以前のモデル)を見てみたら3台中2台は同じような状態だったので、必要経費と思うしかない。

Tags: 250DUKE

2018-09-02 (Sun) [長年日記]

_ タイヤ&プラグ交換

photo

リアタイヤが終わってしまったのでタイヤを前後とも交換した。IRCの新しいラジアルタイヤも気になったけど、結局定番(?)のMichelin Pilot Street Radialで、リアはサイズを変えて140/70R17にしてみた。

ついでにプラグもNGKのLKAR7ARX 11Pに換えてもらった。

整備が終わっていざ帰ろうとしたらフロントからカラカラと異音が……。250DUKEはホイールカラーの精度のせいか個体によってセンターが出づらいらしく、調整してもらっていったん異音は収まったけど、これで駄目ならVORGUEのカラーとかに換えないと駄目かもとのこと。

今までは特に問題なかったので何事もないといいけど。

走行距離: 10684km

Tags: 250DUKE