class Atomic
def compare_and_set(old_value, new_value)
def compare_and_set(old_value, new_value) return false unless @mutex.try_lock begin return false unless @value.equal? old_value @value = new_value ensure @mutex.unlock end true end
def compare_and_set(expected, new)
def compare_and_set(expected, new) if expected.kind_of? Numeric while true old = get return false unless old.kind_of? Numeric return false unless old == expected result = _compare_and_set(old, new) return result if result end else _compare_and_set(expected, new) end end
def get
def get @mutex.synchronize { @value } end
def get_and_set(new_value)
def get_and_set(new_value) @mutex.synchronize do old_value = @value @value = new_value old_value end end
def initialize(value = nil)
Portable/generic (but not very memory or scheduling-efficient) fallback
def initialize(value = nil) @mutex = Mutex.new @value = value end
def set(new_value)
def set(new_value) @mutex.synchronize { @value = new_value } end
def try_update
def try_update old_value = @ref.get new_value = yield old_value unless @ref.compare_and_set(old_value, new_value) if $VERBOSE raise ConcurrentUpdateError, "Update failed" else raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE end end new_value end
def try_update
def try_update old_value = get new_value = yield old_value unless compare_and_set(old_value, new_value) if $VERBOSE raise ConcurrentUpdateError, "Update failed" else raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE end end new_value end
def update
with the block's result. May retry if the value changes
Pass the current value to the given block, replacing it
def update true until @ref.compare_and_set(old_value = @ref.get, new_value = yield(old_value)) new_value end
def update
with the block's result. May retry if the value changes
Pass the current value to the given block, replacing it
def update true until compare_and_set(old_value = get, new_value = yield(old_value)) new_value end