Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #14533 -- Make django signals more thread-safe. Thanks milosu f…

…or the patch!

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14662 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit f27e6f0dd198309e0d965ca78bf1c5fd04a29f8e 1 parent 14abb7c
@HonzaKral HonzaKral authored
Showing with 35 additions and 18 deletions.
  1. +35 −18 django/dispatch/dispatcher.py
View
53 django/dispatch/dispatcher.py
@@ -1,4 +1,5 @@
import weakref
+import threading
from django.dispatch import saferef
@@ -30,6 +31,7 @@ def __init__(self, providing_args=None):
if providing_args is None:
providing_args = []
self.providing_args = set(providing_args)
+ self.lock = threading.Lock()
def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
"""
@@ -97,11 +99,15 @@ def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
if weak:
receiver = saferef.safeRef(receiver, onDelete=self._remove_receiver)
- for r_key, _ in self.receivers:
- if r_key == lookup_key:
- break
- else:
- self.receivers.append((lookup_key, receiver))
+ try:
+ self.lock.acquire()
+ for r_key, _ in self.receivers:
+ if r_key == lookup_key:
+ break
+ else:
+ self.receivers.append((lookup_key, receiver))
+ finally:
+ self.lock.release()
def disconnect(self, receiver=None, sender=None, weak=True, dispatch_uid=None):
"""
@@ -130,11 +136,15 @@ def disconnect(self, receiver=None, sender=None, weak=True, dispatch_uid=None):
else:
lookup_key = (_make_id(receiver), _make_id(sender))
- for index in xrange(len(self.receivers)):
- (r_key, _) = self.receivers[index]
- if r_key == lookup_key:
- del self.receivers[index]
- break
+ try:
+ self.lock.acquire()
+ for index in xrange(len(self.receivers)):
+ (r_key, _) = self.receivers[index]
+ if r_key == lookup_key:
+ del self.receivers[index]
+ break
+ finally:
+ self.lock.release()
def send(self, sender, **named):
"""
@@ -227,14 +237,21 @@ def _remove_receiver(self, receiver):
Remove dead receivers from connections.
"""
- to_remove = []
- for key, connected_receiver in self.receivers:
- if connected_receiver == receiver:
- to_remove.append(key)
- for key in to_remove:
- for idx, (r_key, _) in enumerate(self.receivers):
- if r_key == key:
- del self.receivers[idx]
+ try:
+ self.lock.acquire()
+ to_remove = []
+ for key, connected_receiver in self.receivers:
+ if connected_receiver == receiver:
+ to_remove.append(key)
+ for key in to_remove:
+ 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:
+ del self.receivers[last_idx-idx]
+ finally:
+ self.lock.release()
def receiver(signal, **kwargs):
Please sign in to comment.
Something went wrong with that request. Please try again.