Fixed #14533 -- Make django signals more thread-safe. Thanks milosu for the patch!
git-svn-id: http://code.djangoproject.com/svn/django/trunk@14662 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
14abb7c52c
commit
f27e6f0dd1
|
@ -1,4 +1,5 @@
|
||||||
import weakref
|
import weakref
|
||||||
|
import threading
|
||||||
|
|
||||||
from django.dispatch import saferef
|
from django.dispatch import saferef
|
||||||
|
|
||||||
|
@ -30,6 +31,7 @@ class Signal(object):
|
||||||
if providing_args is None:
|
if providing_args is None:
|
||||||
providing_args = []
|
providing_args = []
|
||||||
self.providing_args = set(providing_args)
|
self.providing_args = set(providing_args)
|
||||||
|
self.lock = threading.Lock()
|
||||||
|
|
||||||
def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
|
def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
|
||||||
"""
|
"""
|
||||||
|
@ -97,11 +99,15 @@ class Signal(object):
|
||||||
if weak:
|
if weak:
|
||||||
receiver = saferef.safeRef(receiver, onDelete=self._remove_receiver)
|
receiver = saferef.safeRef(receiver, onDelete=self._remove_receiver)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.lock.acquire()
|
||||||
for r_key, _ in self.receivers:
|
for r_key, _ in self.receivers:
|
||||||
if r_key == lookup_key:
|
if r_key == lookup_key:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
self.receivers.append((lookup_key, receiver))
|
self.receivers.append((lookup_key, receiver))
|
||||||
|
finally:
|
||||||
|
self.lock.release()
|
||||||
|
|
||||||
def disconnect(self, receiver=None, sender=None, weak=True, dispatch_uid=None):
|
def disconnect(self, receiver=None, sender=None, weak=True, dispatch_uid=None):
|
||||||
"""
|
"""
|
||||||
|
@ -130,11 +136,15 @@ class Signal(object):
|
||||||
else:
|
else:
|
||||||
lookup_key = (_make_id(receiver), _make_id(sender))
|
lookup_key = (_make_id(receiver), _make_id(sender))
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.lock.acquire()
|
||||||
for index in xrange(len(self.receivers)):
|
for index in xrange(len(self.receivers)):
|
||||||
(r_key, _) = self.receivers[index]
|
(r_key, _) = self.receivers[index]
|
||||||
if r_key == lookup_key:
|
if r_key == lookup_key:
|
||||||
del self.receivers[index]
|
del self.receivers[index]
|
||||||
break
|
break
|
||||||
|
finally:
|
||||||
|
self.lock.release()
|
||||||
|
|
||||||
def send(self, sender, **named):
|
def send(self, sender, **named):
|
||||||
"""
|
"""
|
||||||
|
@ -227,14 +237,21 @@ class Signal(object):
|
||||||
Remove dead receivers from connections.
|
Remove dead receivers from connections.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.lock.acquire()
|
||||||
to_remove = []
|
to_remove = []
|
||||||
for key, connected_receiver in self.receivers:
|
for key, connected_receiver in self.receivers:
|
||||||
if connected_receiver == receiver:
|
if connected_receiver == receiver:
|
||||||
to_remove.append(key)
|
to_remove.append(key)
|
||||||
for key in to_remove:
|
for key in to_remove:
|
||||||
for idx, (r_key, _) in enumerate(self.receivers):
|
last_idx = len(self.receivers) - 1
|
||||||
|
# enumerate in reverse order so that indexes are valid even
|
||||||
|
# after we delete some items
|
||||||
|
for idx, (r_key, _) in enumerate(reversed(self.receivers)):
|
||||||
if r_key == key:
|
if r_key == key:
|
||||||
del self.receivers[idx]
|
del self.receivers[last_idx-idx]
|
||||||
|
finally:
|
||||||
|
self.lock.release()
|
||||||
|
|
||||||
|
|
||||||
def receiver(signal, **kwargs):
|
def receiver(signal, **kwargs):
|
||||||
|
|
Loading…
Reference in New Issue