Tbpgr Blog

Recruiting Operations tbpgr(てぃーびー) のブログ

マルチスレッドデザインパターン | Single Threaded Execution

概要

Single Threaded Execution

詳細

Single Threaded Executionは同時に一つのスレッドしか処理出来ないようなケースに
適用するパターンです。
Single Threaded Executionは別名Critical Section/Critical Regionとも呼ばれる。

サンプル仕様

ユーザーがロック式のバージョン管理ソフト「VisualSourceSafe」を利用することを想定します。
ユーザーはソースコードを編集するとユーザー名とソースコードをセットでVisualSourceSafeにコミットします。
この際、ユーザー名の登録とソースコードの登録の間には長い処理があると想定します。

各ユーザーは以下の様なコードを書きます
※#{user_name}部は各ユーザー名が入る

"hello #{user_name}"

サンプルUML

スレッドセーフではないパターン

# encoding: utf-8
require "pp"

class VisualSourceSafe
  attr_accessor :source,:user

  def commit(user, source)
    @user = user
    sleep 1
    @source = source
  end
end

class User
  attr_accessor :name

  def initialize(name)
    @name = name
  end

  def commit(vss, user, source)
    vss.commit user, source
  end
end

vss = VisualSourceSafe.new
threads = %w[hoge hage hige].map do |user|
  Thread.new do |t|
    User.new(user).commit(vss, user, "hello #{user}")
    pp vss
  end
end

threads.each(&:join)

スレッドセーフではないパターンの出力

#<VisualSourceSafe:0x2945970 @source="hello hoge", @user="hige">
#<VisualSourceSafe:0x2945970 @source="hello hage", @user="hige">
#<VisualSourceSafe:0x2945970 @source="hello hige", @user="hige">

スレッドセーフなパターン(Single Threaded Executionパターン)

# encoding: utf-8
require "pp"
require "thread"

class VisualSourceSafe
  attr_accessor :source,:user

  def initialize
    @m = Mutex.new
  end

  def commit(user, source)
    @m.synchronize {
      @user = user
      sleep 1
      @source = source
    }
  end
end

class User
  attr_accessor :name

  def initialize(name)
    @name = name
  end

  def commit(vss)
    vss.commit name, "hello #{name}"
  end
end

vss = VisualSourceSafe.new
threads = %w[hoge hage hige].map do |user|
  Thread.new do |t|
    User.new(user).commit(vss)
    pp vss
  end
end

threads.each(&:join)

スレッドセーフなパターンの出力

#<VisualSourceSafe:0x28feb70
 @m=#<Mutex:0x28feb40>,
 @source="hello hoge",
 @user="hoge">
#<VisualSourceSafe:0x28feb70
 @m=#<Mutex:0x28feb40>,
 @source="hello hage",
 @user="hage">
#<VisualSourceSafe:0x28feb70
 @m=#<Mutex:0x28feb40>,
 @source="hello hige",
 @user="hige">
[Finished in 3.1s]