Make injection and singleton scope thread safe

This commit is contained in:
Jakub Stasiak 2013-01-16 22:02:47 +00:00
parent 40fe997913
commit 9cd643964a
3 changed files with 63 additions and 0 deletions

View File

@ -410,6 +410,14 @@ class instance on the time of method call::
After such call all ``inject``-decorated methods will work just as you'd expect After such call all ``inject``-decorated methods will work just as you'd expect
them to work. them to work.
Thread safety
=============
The following functions are thread safe:
* ``Injector.get``
* injection provided by ``inject`` decorator (please note, however, that it doesn't say anything about decorated function thread safety)
Footnote Footnote
======== ========
This framework is similar to snake-guice, but aims for simplification. This framework is similar to snake-guice, but aims for simplification.

View File

@ -29,6 +29,17 @@ __author__ = 'Alec Thomas <alec@swapoff.org>'
__version__ = '0.5.2' __version__ = '0.5.2'
__version_tag__ = '' __version_tag__ = ''
def synchronized(lock):
def outside_wrapper(function):
@functools.wraps(function)
def wrapper(*args, **kwargs):
with lock:
return function(*args, **kwargs)
return wrapper
return outside_wrapper
lock = threading.RLock()
class Error(Exception): class Error(Exception):
"""Base exception.""" """Base exception."""
@ -353,6 +364,7 @@ class SingletonScope(Scope):
def configure(self): def configure(self):
self._context = {} self._context = {}
@synchronized(lock)
def get(self, key, provider): def get(self, key, provider):
try: try:
return self._context[key] return self._context[key]
@ -493,6 +505,7 @@ class Injector(object):
""" """
instance.__injector__ = self instance.__injector__ = self
@synchronized(lock)
def args_to_inject(self, function, bindings, owner_key): def args_to_inject(self, function, bindings, owner_key):
"""Inject arguments into a function. """Inject arguments into a function.

View File

@ -11,6 +11,7 @@
"""Functional tests for the Pollute dependency injection framework.""" """Functional tests for the Pollute dependency injection framework."""
from contextlib import contextmanager from contextlib import contextmanager
from time import sleep
import abc import abc
import threading import threading
@ -664,3 +665,44 @@ def test_assisted_builder_works_when_injected():
injector = Injector() injector = Injector()
x = injector.get(X) x = injector.get(X)
assert ((x.obj.a, x.obj.b) == (str(), 234)) assert ((x.obj.a, x.obj.b) == (str(), 234))
class TestThreadSafety(object):
def setup(self):
def configure(binder):
binder.bind(str, to=lambda: sleep(1) and 'this is str')
class XXX(object):
@inject(s=str)
def __init__(self, s):
pass
self.injector = Injector(configure)
self.cls = XXX
def gather_results(self, count):
objects = []
lock = threading.Lock()
def target():
o = self.injector.get(self.cls)
with lock:
objects.append(o)
threads = [threading.Thread(target=target) for i in range(2)]
for t in threads:
t.start()
for t in threads:
t.join()
return objects
def test_injection_is_thread_safe(self):
objects = self.gather_results(2)
assert (len(objects) == 2)
def test_singleton_scope_is_thread_safe(self):
self.injector.binder.bind(self.cls, scope=singleton)
a, b = self.gather_results(2)
assert (a is b)