Skip to content

Instantly share code, notes, and snippets.

@mikbe
Created June 17, 2011 13:30
Show Gist options
  • Select an option

  • Save mikbe/1031419 to your computer and use it in GitHub Desktop.

Select an option

Save mikbe/1031419 to your computer and use it in GitHub Desktop.

Revisions

  1. mikbe revised this gist Jun 17, 2011. 1 changed file with 16 additions and 8 deletions.
    24 changes: 16 additions & 8 deletions thread_safe.rb
    Original file line number Diff line number Diff line change
    @@ -33,30 +33,35 @@ def baz
    end


    f = nil
    f = Foo.new
    f2 = Foo.new

    lastBaz1 = -2
    lastBaz2 = -2
    baz1 = -1
    baz2 = -1
    count = 0
    last_one = ""
    show_once = true
    while baz1 == baz2

    last_one = "f.bar: #{f.bar}; baz1: #{baz1}; baz2: #{baz2}"
    f = Foo.new

    lastBaz1, lastBaz2 = baz1, baz2

    wait_til = Time.now + 0.01
    Thread.new {sleep (wait_til - Time.now); baz1 = f.baz }
    Thread.new {sleep (wait_til - Time.now); baz2 = f.baz }
    t1 = Thread.new {sleep ((Time.now + 0.01 )- Time.now); baz1 = f.baz }
    t2 = Thread.new {sleep ((Time.now + 0.01) - Time.now); baz2 = f.baz }

    # make sure both threads are done
    time_out = 0
    sleep 0.01 while (baz2 == lastBaz2 || baz1 == lastBaz1) && (time_out += 1) < 100
    sleep 0.01 while (baz2 == lastBaz2 || baz1 == lastBaz1) && (time_out += 1) < 10
    if time_out == 10
    # Make sure it wasn't an error in the thread that caused the timeout
    t1.join
    t2.join
    puts "timeout reached"
    break
    end
    puts "#{f.threadsafe_mutex}: #{f.bar}" if (count+=1) % 100 == 0
    GC.start if count % 100 == 0

    # Verify instances are getting their own mutexes
    if show_once
    @@ -71,3 +76,6 @@ def baz
    puts "Thread collision: should never get here"
    puts "previous: #{last_one}" # <= Prove it's not remembering value from last iteration but is a real collision
    puts "current: f.bar: #{f.bar}; baz1: #{baz1}; baz2: #{baz2}"
    puts "Class mutex: #{f.class.threadsafe_class_mutex}"
    puts "instance mutex: #{f.threadsafe_mutex}"
    puts "instance mutex: #{f2.threadsafe_mutex}"
  2. mikbe revised this gist Jun 17, 2011. 1 changed file with 19 additions and 16 deletions.
    35 changes: 19 additions & 16 deletions thread_safe.rb
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@ module ThreadSafe

    def self.included(base)
    base.extend(ThreadSafeClassMethods)
    base.threadsafe_class_mutex = Mutex.new # <= This should be threadsafe by its very nature
    base.threadsafe_class_mutex = Mutex.new
    end

    module ThreadSafeClassMethods
    @@ -33,38 +33,41 @@ def baz
    end


    f = Foo.new
    f = nil
    f2 = Foo.new

    lastBaz1 = -2
    lastBaz2 = -2
    baz1 = -1
    baz2 = -1
    count = 0
    last_one = ""
    show_once = true
    while baz1 == baz2
    last_one = "f.bar: #{f.bar}; baz1: #{baz1}; baz2: #{baz2}"
    f.bar = nil

    f = Foo.new

    lastBaz1, lastBaz2 = baz1, baz2

    wait_til = Time.now + 0.01
    Thread.new {sleep (wait_til - Time.now); baz1 = f.baz }
    Thread.new {sleep (wait_til - Time.now); baz2 = f.baz }
    sleep 0.02
    count += 1
    if count == 100
    puts "working: #{last_one}"
    count = 0
    end


    # make sure both threads are done
    time_out = 0
    sleep 0.01 while (baz2 == lastBaz2 || baz1 == lastBaz1) && (time_out += 1) < 100
    puts "#{f.threadsafe_mutex}: #{f.bar}" if (count+=1) % 100 == 0

    # Verify instances are getting their own mutexes
    if show_once
    show_once = false
    # only want to run these after the classes have had a chance to instnatiate the mutexes,
    # not force them to be instantiated (thus negating the reason for the test)
    puts "Class mutex: #{f.class.threadsafe_class_mutex}"
    puts "instance mutex: #{f.threadsafe_mutex}"
    puts "instance mutex: #{f2.threadsafe_mutex}" # Just to verify instances are getting their own mutexes
    puts "instance mutex: #{f2.threadsafe_mutex}"
    end

    end
    puts
    puts "Thread collision"
    puts "previous: #{last_one}" # Just to prove it's not remembering value from last iteration but is a real collision
    puts "Thread collision: should never get here"
    puts "previous: #{last_one}" # <= Prove it's not remembering value from last iteration but is a real collision
    puts "current: f.bar: #{f.bar}; baz1: #{baz1}; baz2: #{baz2}"
  3. mikbe created this gist Jun 17, 2011.
    70 changes: 70 additions & 0 deletions thread_safe.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,70 @@
    require 'thread'

    module ThreadSafe

    def self.included(base)
    base.extend(ThreadSafeClassMethods)
    base.threadsafe_class_mutex = Mutex.new # <= This should be threadsafe by its very nature
    end

    module ThreadSafeClassMethods
    attr_accessor :threadsafe_class_mutex
    end

    def threadsafe_mutex
    self.class.threadsafe_class_mutex.synchronize {
    @mutex ||= Mutex.new
    }
    end

    end

    class Foo
    include ThreadSafe

    attr_accessor :bar

    def baz
    threadsafe_mutex.synchronize {
    @bar ||= rand(10000000000)
    }
    end

    end


    f = Foo.new
    f2 = Foo.new

    baz1 = -1
    baz2 = -1
    count = 0
    last_one = ""
    show_once = true
    while baz1 == baz2
    last_one = "f.bar: #{f.bar}; baz1: #{baz1}; baz2: #{baz2}"
    f.bar = nil
    wait_til = Time.now + 0.01
    Thread.new {sleep (wait_til - Time.now); baz1 = f.baz }
    Thread.new {sleep (wait_til - Time.now); baz2 = f.baz }
    sleep 0.02
    count += 1
    if count == 100
    puts "working: #{last_one}"
    count = 0
    end

    if show_once
    show_once = false
    # only want to run these after the classes have had a chance to instnatiate the mutexes,
    # not force them to be instantiated (thus negating the reason for the test)
    puts "Class mutex: #{f.class.threadsafe_class_mutex}"
    puts "instance mutex: #{f.threadsafe_mutex}"
    puts "instance mutex: #{f2.threadsafe_mutex}" # Just to verify instances are getting their own mutexes
    end

    end
    puts
    puts "Thread collision"
    puts "previous: #{last_one}" # Just to prove it's not remembering value from last iteration but is a real collision
    puts "current: f.bar: #{f.bar}; baz1: #{baz1}; baz2: #{baz2}"