Search code examples
rubyexceptionmutexsynchronize

How exactly exception unlocks mutex?


This simple test mostly results as
(1) rescue break, m.locked?: false
but sometimes I can see
(1) rescue break, m.locked?: true

m = Mutex.new

6.times do

    Thread.new do
        begin
            m.synchronize do
                puts 't1 action'
                3.times do
                    puts '.'
                    sleep 0.5
                end
                raise 'Break'
            end
        rescue 
            puts "(1) rescue break, m.locked?: #{m.locked?}"
            m.synchronize do
                sleep 0.1
            end
            puts '(2) after m {sleep}'
            sleep 0.1
            puts 'rescue break 2'
        end
    end

    sleep 0.1
    t2 = Thread.new do
        puts 't2 waiting for mutex'
        m.synchronize do
            puts '(3) t2 action'
        end
    end

    t2.join
    sleep 0.2
    puts;puts;
end

I expected that inside the rescue block mutex will be always unlocked.

Environment: Ruby v2.6.3.62 (2019-04-16) [x64-mingw32]


Solution

  • Nobody promised that the processor would stop the world, waiting for your action :) That said, between

    raise 'Break'
    

    and

    puts "(1) rescue break, m.locked?: #{m.locked?}"
    

    there is another thread that might get the execution time and in turn lock the mutex.


    Please also note, that

        raise 'Break'
      end
    rescue 
      puts "(1) rescue break, m.locked?: #{m.locked?}"
    

    is effectively the same as

      end
      puts "(1) rescue break, m.locked?: #{m.locked?}"
    

    In the latter snippet, it should be clear that m might be either locked by another thread, or not; we have it just released, so no promise.