Source code for atomos.atomic

# -*- coding: utf-8 -*-
'''
atomos.atomic

Atomic primitives.
'''

import types

import six

import atomos.util as util

if six.PY3:
    long = int


[docs]class AtomicReference(object): ''' A reference to an object which allows atomic manipulation semantics. AtomicReferences are particularlly useful when an object cannot otherwise be manipulated atomically. ''' def __init__(self, value=None): self._value = value self._lock = util.ReadersWriterLock() def __repr__(self): return util.repr(__name__, self, self._value)
[docs] def get(self): ''' Returns the value. ''' with self._lock.shared: return self._value
[docs] def set(self, value): ''' Atomically sets the value to `value`. :param value: The value to set. ''' with self._lock.exclusive: self._value = value return value
[docs] def get_and_set(self, value): ''' Atomically sets the value to `value` and returns the old value. :param value: The value to set. ''' with self._lock.exclusive: oldval = self._value self._value = value return oldval
[docs] def compare_and_set(self, expect, update): ''' Atomically sets the value to `update` if the current value is equal to `expect`. :param expect: The expected current value. :param update: The value to set if and only if `expect` equals the current value. ''' with self._lock.exclusive: if self._value == expect: self._value = update return True return False
[docs]class AtomicBoolean(AtomicReference): ''' A boolean value whichs allows atomic manipulation semantics. ''' def __init__(self, value=False): super(AtomicBoolean, self).__init__(value=value) # We do not need a locked get since a boolean is not a complex data type.
[docs] def get(self): ''' Returns the value. ''' return self._value
def __setattr__(self, name, value): # Ensure the `value` attribute is always a bool. if name == '_value' and not isinstance(value, types.BooleanType): raise TypeError('_value must be of type bool') super(AtomicBoolean, self).__setattr__(name, value)
class AtomicNumber(AtomicReference): ''' AtomicNumber object super type. Contains common methods for AtomicInteger, AtomicLong, and AtomicFloat. ''' # We do not need a locked get since numbers are not complex data types. def get(self): ''' Returns the value. ''' return self._value def add_and_get(self, delta): ''' Atomically adds `delta` to the current value. :param delta: The delta to add. ''' with self._lock.exclusive: self._value += delta return self._value def get_and_add(self, delta): ''' Atomically adds `delta` to the current value and returns the old value. :param delta: The delta to add. ''' with self._lock.exclusive: oldval = self._value self._value += delta return oldval def subtract_and_get(self, delta): ''' Atomically subtracts `delta` from the current value. :param delta: The delta to subtract. ''' with self._lock.exclusive: self._value -= delta return self._value def get_and_subtract(self, delta): ''' Atomically subtracts `delta` from the current value and returns the old value. :param delta: The delta to subtract. ''' with self._lock.exclusive: oldval = self._value self._value -= delta return oldval
[docs]class AtomicInteger(AtomicNumber): ''' An integer value which allows atomic manipulation semantics. ''' def __init__(self, value=0): super(AtomicInteger, self).__init__(value=value) def __setattr__(self, name, value): # Ensure the `_value` attribute is always an int. if name == '_value' and not isinstance(value, int): raise TypeError('_value must be of type int') super(AtomicInteger, self).__setattr__(name, value)
[docs]class AtomicLong(AtomicNumber): ''' A long value which allows atomic manipulation semantics. ''' def __init__(self, value=long(0)): super(AtomicLong, self).__init__(value=value) def __setattr__(self, name, value): # Ensure the `_value` attribute is always a long. if name == '_value' and not isinstance(value, long): raise TypeError('_value must be of type long') super(AtomicLong, self).__setattr__(name, value)
[docs]class AtomicFloat(AtomicNumber): ''' A float value which allows atomic manipulation semantics. ''' def __init__(self, value=float(0)): super(AtomicFloat, self).__init__(value=value) def __setattr__(self, name, value): # Ensure the `_value` attribute is always a float. if name == '_value' and not isinstance(value, types.FloatType): raise TypeError('_value must be of type float') super(AtomicFloat, self).__setattr__(name, value)