import contextvars import unittest from threading import Event, Thread from test.support import threading_helper @threading_helper.requires_working_threading() class TestContext(unittest.TestCase): def test_racing_read_write(self): # gh-154535: reading a Context object from one thread while another # thread sets variables in it used to crash. The readers looked at # Context.ctx_vars without owning a reference to it, so the writer # could deallocate the mapping while a reader was walking it. ctx = contextvars.Context() cvars = [contextvars.ContextVar(f"cvar{i}") for i in range(64)] done = Event() errors = [] def writer(): def body(): i = 0 while not done.is_set(): cvars[i % len(cvars)].set(i) i += 1 try: ctx.run(body) except BaseException as e: errors.append(e) def reader(): try: for _ in range(200): ctx.copy() len(ctx) list(ctx) list(ctx.items()) list(ctx.keys()) list(ctx.values()) cvars[0] in ctx ctx.get(cvars[0]) ctx == ctx except BaseException as e: errors.append(e) finally: done.set() threads = [Thread(target=writer)] threads += [Thread(target=reader) for _ in range(4)] with threading_helper.start_threads(threads, done.set): pass self.assertEqual(errors, [], msg=f"unexpected errors: {errors}") if __name__ == "__main__": unittest.main()