Skip to content

Commit f27e6f0

Browse files
committed
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
1 parent 14abb7c commit f27e6f0

File tree

1 file changed

+35
-18
lines changed

1 file changed

+35
-18
lines changed

django/dispatch/dispatcher.py

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import weakref
2+
import threading
23

34
from django.dispatch import saferef
45

@@ -30,6 +31,7 @@ def __init__(self, providing_args=None):
3031
if providing_args is None:
3132
providing_args = []
3233
self.providing_args = set(providing_args)
34+
self.lock = threading.Lock()
3335

3436
def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
3537
"""
@@ -97,11 +99,15 @@ def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
9799
if weak:
98100
receiver = saferef.safeRef(receiver, onDelete=self._remove_receiver)
99101

100-
for r_key, _ in self.receivers:
101-
if r_key == lookup_key:
102-
break
103-
else:
104-
self.receivers.append((lookup_key, receiver))
102+
try:
103+
self.lock.acquire()
104+
for r_key, _ in self.receivers:
105+
if r_key == lookup_key:
106+
break
107+
else:
108+
self.receivers.append((lookup_key, receiver))
109+
finally:
110+
self.lock.release()
105111

106112
def disconnect(self, receiver=None, sender=None, weak=True, dispatch_uid=None):
107113
"""
@@ -130,11 +136,15 @@ def disconnect(self, receiver=None, sender=None, weak=True, dispatch_uid=None):
130136
else:
131137
lookup_key = (_make_id(receiver), _make_id(sender))
132138

133-
for index in xrange(len(self.receivers)):
134-
(r_key, _) = self.receivers[index]
135-
if r_key == lookup_key:
136-
del self.receivers[index]
137-
break
139+
try:
140+
self.lock.acquire()
141+
for index in xrange(len(self.receivers)):
142+
(r_key, _) = self.receivers[index]
143+
if r_key == lookup_key:
144+
del self.receivers[index]
145+
break
146+
finally:
147+
self.lock.release()
138148

139149
def send(self, sender, **named):
140150
"""
@@ -227,14 +237,21 @@ def _remove_receiver(self, receiver):
227237
Remove dead receivers from connections.
228238
"""
229239

230-
to_remove = []
231-
for key, connected_receiver in self.receivers:
232-
if connected_receiver == receiver:
233-
to_remove.append(key)
234-
for key in to_remove:
235-
for idx, (r_key, _) in enumerate(self.receivers):
236-
if r_key == key:
237-
del self.receivers[idx]
240+
try:
241+
self.lock.acquire()
242+
to_remove = []
243+
for key, connected_receiver in self.receivers:
244+
if connected_receiver == receiver:
245+
to_remove.append(key)
246+
for key in to_remove:
247+
last_idx = len(self.receivers) - 1
248+
# enumerate in reverse order so that indexes are valid even
249+
# after we delete some items
250+
for idx, (r_key, _) in enumerate(reversed(self.receivers)):
251+
if r_key == key:
252+
del self.receivers[last_idx-idx]
253+
finally:
254+
self.lock.release()
238255

239256

240257
def receiver(signal, **kwargs):

0 commit comments

Comments
 (0)