Issue #28427: old keys should not remove new values from
WeakValueDictionary when collecting from another thread.
diff --git a/Lib/weakref.py b/Lib/weakref.py
index def955f..c66943f 100644
--- a/Lib/weakref.py
+++ b/Lib/weakref.py
@@ -18,7 +18,8 @@
      proxy,
      CallableProxyType,
      ProxyType,
-     ReferenceType)
+     ReferenceType,
+     _remove_dead_weakref)
 
 from _weakrefset import WeakSet, _IterationGuard
 
@@ -58,7 +59,9 @@
                 if self._iterating:
                     self._pending_removals.append(wr.key)
                 else:
-                    del self.data[wr.key]
+                    # Atomic removal is necessary since this function
+                    # can be called asynchronously by the GC
+                    _remove_dead_weakref(self.data, wr.key)
         self._remove = remove
         # A list of keys to be removed
         self._pending_removals = []
@@ -71,9 +74,12 @@
         # We shouldn't encounter any KeyError, because this method should
         # always be called *before* mutating the dict.
         while l:
-            del d[l.pop()]
+            key = l.pop()
+            _remove_dead_weakref(d, key)
 
     def __getitem__(self, key):
+        if self._pending_removals:
+            self._commit_removals()
         o = self.data[key]()
         if o is None:
             raise KeyError, key
@@ -86,6 +92,8 @@
         del self.data[key]
 
     def __contains__(self, key):
+        if self._pending_removals:
+            self._commit_removals()
         try:
             o = self.data[key]()
         except KeyError:
@@ -93,6 +101,8 @@
         return o is not None
 
     def has_key(self, key):
+        if self._pending_removals:
+            self._commit_removals()
         try:
             o = self.data[key]()
         except KeyError:
@@ -113,6 +123,8 @@
         self.data.clear()
 
     def copy(self):
+        if self._pending_removals:
+            self._commit_removals()
         new = WeakValueDictionary()
         for key, wr in self.data.items():
             o = wr()
@@ -124,6 +136,8 @@
 
     def __deepcopy__(self, memo):
         from copy import deepcopy
+        if self._pending_removals:
+            self._commit_removals()
         new = self.__class__()
         for key, wr in self.data.items():
             o = wr()
@@ -132,6 +146,8 @@
         return new
 
     def get(self, key, default=None):
+        if self._pending_removals:
+            self._commit_removals()
         try:
             wr = self.data[key]
         except KeyError:
@@ -145,6 +161,8 @@
                 return o
 
     def items(self):
+        if self._pending_removals:
+            self._commit_removals()
         L = []
         for key, wr in self.data.items():
             o = wr()
@@ -153,6 +171,8 @@
         return L
 
     def iteritems(self):
+        if self._pending_removals:
+            self._commit_removals()
         with _IterationGuard(self):
             for wr in self.data.itervalues():
                 value = wr()
@@ -160,6 +180,8 @@
                     yield wr.key, value
 
     def iterkeys(self):
+        if self._pending_removals:
+            self._commit_removals()
         with _IterationGuard(self):
             for k in self.data.iterkeys():
                 yield k
@@ -176,11 +198,15 @@
         keep the values around longer than needed.
 
         """
+        if self._pending_removals:
+            self._commit_removals()
         with _IterationGuard(self):
             for wr in self.data.itervalues():
                 yield wr
 
     def itervalues(self):
+        if self._pending_removals:
+            self._commit_removals()
         with _IterationGuard(self):
             for wr in self.data.itervalues():
                 obj = wr()
@@ -212,13 +238,13 @@
             return o
 
     def setdefault(self, key, default=None):
+        if self._pending_removals:
+            self._commit_removals()
         try:
             o = self.data[key]()
         except KeyError:
             o = None
         if o is None:
-            if self._pending_removals:
-                self._commit_removals()
             self.data[key] = KeyedRef(default, self._remove, key)
             return default
         else:
@@ -254,9 +280,13 @@
         keep the values around longer than needed.
 
         """
+        if self._pending_removals:
+            self._commit_removals()
         return self.data.values()
 
     def values(self):
+        if self._pending_removals:
+            self._commit_removals()
         L = []
         for wr in self.data.values():
             o = wr()