sync_attr 
Thread-safe Ruby class and instance attributes
Status
Enterprise Production Ready - In daily use in large multi-threaded application
Introduction
When working in a multi-threaded environment it is important to ensure that
any attributes that are shared across threads are properly protected to ensure
that inconsistent data is not created. Lazy initializing these safe attributes
improves startup times and only creates resources when they are needed.
For example, without sync_attr if two threads attempt to write to the
same attribute at the same time it is not deterministic what the results will be.
This condition is made worse when two threads attempt to initialize class instance
attributes at the same time that could take a second or longer to complete.
A sync_cattr_reader
is ideal for holding data loaded from configuration files.
Also, shared objects, such as connection pools can be safely initialized and
shared in this way across hundreds of threads.
Once initialized all reads are shared without locks since no writer is defined.
Aside from safely sharing reads sync_cattr_accessor
also ensures that data
is not read while it is being modified. The writes are completely thread-safe
ensuring that only one thread is modifying the value at a time and that reads
are suspended until the write is complete.
Features
- Adds thread-safe accessors for class instance attributes.
- Only one thread can read or write the value at any one time.
- Prevents attributes from being read while it is being updated or initialized for
the first time.
- Thread-safe attribute lazy initialization.
Lazy initialization allows class attributes to be loaded only when first read.
As a result it's value can be read for the first time from a database or
configuration file once and only when needed.
- Avoids having to create yet another Rails initializer, when the data can be
fetched or held by a class instance attribute.
- Avoids costly startup initialization when the initialized data may never be accessed.
For example, when Rake tasks are run, they may not need access to everything in
the Rails environment.
- Works with Rails and regular Ruby.
Thread-safe Class Attribute example
Create a reader for a class attribute and lazy initialize its value on the first
attempt to read it. I.e. Lazy initialize the value.
Very useful for initializing shared services that take time to initialize.
In particular services that may not even be called in a specific process,
for example when running rake, or when opening a console.
An optional block can be supplied to initialize the synchronized class attribute
when it is first read. The initializer is thread safe and will block all other
reads to this attribute while it is being initialized. This ensures that the
initializer is only run once and that all threads to call the reader receive the
same value, regardless of how many threads call the reader at the same time.
Example:
require 'sync_attr'
class Person
sync_cattr_reader :name do
'Joe Bloggs'
end
sync_cattr_accessor :age do
21
end
end
puts "The person is #{Person.name} with age #{Person.age}"
Person.age = 22
puts "The person is #{Person.name} now has age #{Person.age}"
Person.age = Proc.new {|age| age += 1 }
puts "The person is #{Person.name} now has age #{Person.age}"
Thread-safe Instance Attribute example
Create a reader for an attribute and lazy initialize its value on the first
attempt to read it. I.e. Lazy initialize the value.
An optional block can be supplied to initialize the synchronized attribute
when it is first read. The initializer is thread safe and will block all other
reads to this attribute while it is being initialized. This ensures that the
initializer is only run once per object and that all threads to call the reader
receive the same value, regardless of how many threads call the reader at the same time.
Example:
require 'sync_attr'
class Person
include SyncAttr::Attributes
sync_attr_reader :name do
'Joe Bloggs'
end
sync_attr_accessor :age do
21
end
end
person = Person.new
puts "The person is #{person.name} with age #{person.age}"
person.age = 22
puts "The person is #{person.name} now has age #{person.age}"
person.age = Proc.new {|age| age += 1 }
puts "The person is #{person.name} now has age #{person.age}"
Install
gem install sync_attr
Meta
This project uses Semantic Versioning.
Authors
Reid Morrison :: reidmo@gmail.com :: @reidmorrison
License
Copyright 2012, 2013, 2014, 2015 Reid Morrison
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.