Neil Macneale
Neil Macneale

Reputation: 341

Ruby Return Within semaphore.synchronize Block

I was wondering if semaphore would release the lock if I did something like this:

def test
  semaphore.syncronize do
    if (access_shared_resource)
      return "Condition A"
    else
      return "Condition B"
    end
  end
end

Will the thread running this function continue holding this lock until it terminates? Or will the return statement release the lock?

Upvotes: 4

Views: 1146

Answers (3)

phundi
phundi

Reputation: 1

You can have a variable before the synchronize method, get your return value assigned to this variable within the block then access the variable with the assigned value after the block execution has completed.

Upvotes: 0

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

Returns from blocks are tricky and might differ between different implementation of ruby in how they rewind the stack frames. Try to avoid returning from block whenever possible (hint: it’s always possible.)

Instead of struggling with returns, use break, which is clean and has very well-defined behaviour:

def test
  semaphore.syncronize do
    if (access_shared_resource)
      break "Condition A"
    else
      break "Condition B"
    end
  end
end

or, if there is some code before natural block leaving present:

def test
  case
    semaphore.syncronize do
      break :continue if (normal_condition)
      if (access_shared_resource)
        break :accessed
      else
        break :not_accessed
      end
    end
  when :accessed then "Condition A"
  when :not_accessed then "Condition B"
  else
    # normal control flow
  end
end

Upvotes: 3

Ivan Yurov
Ivan Yurov

Reputation: 1618

According to documentation it will release once it's done with the block (the one passed to syncronize): https://ruby-doc.org/core-2.5.0/Mutex.html#method-i-synchronize

In order to provide more proofs as this answer was downvoted, here's the implementation of synchronize. I'm no expert in C, but from what I see here, unlocking implemented in ensure, so this mutex will be unlocked on block termination no matter whether it returned or was left via jump: https://github.com/ruby/ruby/blob/2cf3bd5bb2a7c4724e528577d37a883fe80a1122/thread_sync.c#L512

Quick modeling supports this as well: https://repl.it/repls/FailingWearableCodewarrior

Upvotes: 3

Related Questions