The threading and queue APIs

Every class in threading and queue that a round uses: what each call returns, what it blocks on, what a timeout does, what it raises, and a tested example of each, with every output recorded by the build.

Which of these calls return False on a timeout, and which raise?

Lock.acquire, RLock.acquire, Semaphore.acquire, Event.wait and Condition.wait return False, and Condition.wait_for returns the predicate's last value, which is falsy. Thread.join returns None either way, so you call is_alive() afterwards. Queue.get and Queue.put raise queue.Empty and queue.Full. Barrier.wait raises BrokenBarrierError and leaves the barrier broken for every other thread. Learn the three groups; a timed call whose result you ignore is a bug in every one of them.

When should I write my own condition variable instead of using queue.Queue?

When the thing you wait for is not "an item arrived" or "there is room". A latch that opens after n events, a pool that waits for a free connection with a particular property, a cache that waits for a load in flight: each needs a predicate over state you own, and that is what Condition with wait_for is for. When the thing you pass between threads is a stream of work, use queue.Queue. It already holds one lock and two conditions, and the standard library tests it.

Is it safe to use queue.Queue.shutdown in an interview?

Say which Python you are assuming. shutdown and queue.ShutDown arrived in Python 3.13. On 3.12 and earlier the usual way to stop a consumer blocked in get() is a sentinel: put one special value per consumer, and each consumer returns when it takes one. Both are correct; the sentinel works everywhere, and shutdown also refuses new puts, which a sentinel does not.

Why does every test here pass a timeout to join, wait and get?

Because a test that can block for ever turns a bug into a build that never finishes, with no message saying which thread is stuck. A timeout turns the same bug into a failed assertion with a line number. After joining with a timeout, assert that the thread is no longer alive, since join itself returns None whether it timed out or not.

Do I need threading.local in an interview answer?

Rarely. It comes up when a question involves per-request context in a threaded server, or a resource that cannot be shared between threads, such as a database connection that is not thread-safe. Know that each thread sees its own attributes on the same object, that a new thread starts with none of them, and that a thread pool reuses threads, so a value left behind by one task is visible to the next task on that thread.