def test_trashcan_threads(self): # Issue #13992: trashcan mechanism should be thread-safe NESTING = 60 N_THREADS = 2 def sleeper_gen(): """A generator that releases the GIL when closed or dealloc'ed.""" try: yield finally: time.sleep(0.000001) class C(list): # Appending to a list is atomic, which avoids the use of a lock. inits = [] dels = [] def __init__(self, alist): self[:] = alist C.inits.append(None) def __del__(self): # This __del__ is called by subtype_dealloc(). C.dels.append(None) # `g` will release the GIL when garbage-collected. This # helps assert subtype_dealloc's behaviour when threads # switch in the middle of it. g = sleeper_gen() next(g) # Now that __del__ is finished, subtype_dealloc will proceed # to call list_dealloc, which also uses the trashcan mechanism. def make_nested(): """Create a sufficiently nested container object so that the trashcan mechanism is invoked when deallocating it.""" x = C([]) for i in range(NESTING): x = [C([x])] del x def run_thread(): """Exercise make_nested() in a loop.""" while not exit: make_nested() old_switchinterval = sys.getswitchinterval() sys.setswitchinterval(1e-5) try: exit = [] threads = [] for i in range(N_THREADS): t = threading.Thread(target=run_thread) threads.append(t) with threading_helper.start_threads(threads, lambda: exit.append(1)): time.sleep(1.0) finally: sys.setswitchinterval(old_switchinterval) gc.collect() self.assertEqual(len(C.inits), len(C.dels))
def testThreading(self): # Issue #7205: Using a BZ2File from several threads shouldn't deadlock. data = b"1" * 2**20 nthreads = 10 with BZ2File(self.filename, 'wb') as f: def comp(): for i in range(5): f.write(data) threads = [threading.Thread(target=comp) for i in range(nthreads)] with threading_helper.start_threads(threads): pass
def test_main(self): threads = [TempFileGreedy() for i in range(NUM_THREADS)] with threading_helper.start_threads(threads, startEvent.set): pass ok = sum(t.ok_count for t in threads) errors = [str(t.name) + str(t.errors.getvalue()) for t in threads if t.error_count] msg = "Errors: errors %d ok %d\n%s" % (len(errors), ok, '\n'.join(errors)) self.assertEqual(errors, [], msg) self.assertEqual(ok, NUM_THREADS * FILES_PER_THREAD)
def test_pendingcalls_threaded(self): #do every callback on a separate thread n = 32 #total callbacks threads = [] class foo(object):pass context = foo() context.l = [] context.n = 2 #submits per thread context.nThreads = n // context.n context.nFinished = 0 context.lock = threading.Lock() context.event = threading.Event() threads = [threading.Thread(target=self.pendingcalls_thread, args=(context,)) for i in range(context.nThreads)] with threading_helper.start_threads(threads): self.pendingcalls_wait(context.l, n, context)
def test_derived(self): # Issue 3088: if there is a threads switch inside the __init__ # of a threading.local derived class, the per-thread dictionary # is created but not correctly set on the object. # The first member set may be bogus. import time class Local(self._local): def __init__(self): time.sleep(0.01) local = Local() def f(i): local.x = i # Simply check that the variable is correctly set self.assertEqual(local.x, i) with threading_helper.start_threads(threading.Thread(target=f, args=(i,)) for i in range(10)): pass
def run_threads(self, n_feeders, n_consumers, q, inputs, feed_func, consume_func): results = [] sentinel = None seq = inputs + [sentinel] * n_consumers seq.reverse() rnd = random.Random(42) exceptions = [] def log_exceptions(f): def wrapper(*args, **kwargs): try: f(*args, **kwargs) except BaseException as e: exceptions.append(e) return wrapper feeders = [ threading.Thread(target=log_exceptions(feed_func), args=(q, seq, rnd)) for i in range(n_feeders) ] consumers = [ threading.Thread(target=log_exceptions(consume_func), args=(q, results, sentinel)) for i in range(n_consumers) ] with threading_helper.start_threads(feeders + consumers): pass self.assertFalse(exceptions) self.assertTrue(q.empty()) self.assertEqual(q.qsize(), 0) return results
def check_parallel_module_init(self, mock_os): if imp.lock_held(): # This triggers on, e.g., from test import autotest. raise unittest.SkipTest("can't run when import lock is held") done = threading.Event() for N in (20, 50) * 3: if verbose: print("Trying", N, "threads ...", end=' ') # Make sure that random and modulefinder get reimported freshly for modname in ['random', 'modulefinder']: try: del sys.modules[modname] except KeyError: pass errors = [] done_tasks = [] done.clear() t0 = time.monotonic() with threading_helper.start_threads( threading.Thread(target=task, args=( N, done, done_tasks, errors, )) for i in range(N)): pass completed = done.wait(10 * 60) dt = time.monotonic() - t0 if verbose: print("%.1f ms" % (dt * 1e3), flush=True, end=" ") dbg_info = 'done: %s/%s' % (len(done_tasks), N) self.assertFalse(errors, dbg_info) self.assertTrue(completed, dbg_info) if verbose: print("OK.")