diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2010-08-28 18:17:03 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2010-08-28 18:17:03 (GMT) |
commit | 1a9a9d543327397396827642895410183f8902d5 (patch) | |
tree | 56ded308662fe5b0a410edef287cb23133ccc574 /Lib/test | |
parent | 64a38c0eb5b7fd6e4ee5f3e912cff9eda8dd19af (diff) | |
download | cpython-1a9a9d543327397396827642895410183f8902d5.zip cpython-1a9a9d543327397396827642895410183f8902d5.tar.gz cpython-1a9a9d543327397396827642895410183f8902d5.tar.bz2 |
Issue #1868: Eliminate subtle timing issues in thread-local objects by
getting rid of the cached copy of thread-local attribute dictionary.
Diffstat (limited to 'Lib/test')
-rw-r--r-- | Lib/test/test_threading_local.py | 62 |
1 files changed, 61 insertions, 1 deletions
diff --git a/Lib/test/test_threading_local.py b/Lib/test/test_threading_local.py index 0a0a008..acf37a0 100644 --- a/Lib/test/test_threading_local.py +++ b/Lib/test/test_threading_local.py @@ -123,6 +123,67 @@ class BaseLocalTest: self.assertRaises(TypeError, self._local, a=1) self.assertRaises(TypeError, self._local, 1) + def _test_one_class(self, c): + self._failed = "No error message set or cleared." + obj = c() + e1 = threading.Event() + e2 = threading.Event() + + def f1(): + obj.x = 'foo' + obj.y = 'bar' + del obj.y + e1.set() + e2.wait() + + def f2(): + try: + foo = obj.x + except AttributeError: + # This is expected -- we haven't set obj.x in this thread yet! + self._failed = "" # passed + else: + self._failed = ('Incorrectly got value %r from class %r\n' % + (foo, c)) + sys.stderr.write(self._failed) + + t1 = threading.Thread(target=f1) + t1.start() + e1.wait() + t2 = threading.Thread(target=f2) + t2.start() + t2.join() + # The test is done; just let t1 know it can exit, and wait for it. + e2.set() + t1.join() + + self.assertFalse(self._failed, self._failed) + + def test_threading_local(self): + self._test_one_class(self._local) + + def test_threading_local_subclass(self): + class LocalSubclass(self._local): + """To test that subclasses behave properly.""" + self._test_one_class(LocalSubclass) + + def _test_dict_attribute(self, cls): + obj = cls() + obj.x = 5 + self.assertEqual(obj.__dict__, {'x': 5}) + with self.assertRaises(AttributeError): + obj.__dict__ = {} + with self.assertRaises(AttributeError): + del obj.__dict__ + + def test_dict_attribute(self): + self._test_dict_attribute(self._local) + + def test_dict_attribute_subclass(self): + class LocalSubclass(self._local): + """To test that subclasses behave properly.""" + self._test_dict_attribute(LocalSubclass) + class ThreadLocalTest(unittest.TestCase, BaseLocalTest): _local = _thread._local @@ -140,7 +201,6 @@ class ThreadLocalTest(unittest.TestCase, BaseLocalTest): gc.collect() self.assertIs(wr(), None) - class PyThreadingLocalTest(unittest.TestCase, BaseLocalTest): _local = _threading_local.local |