From the docs:
If the calling thread has not acquired the lock when this method is called, a RuntimeError is raised.
This is generally true in all languages. There's several reasons for this. One is that condition variable code generally looks something like:
while not some_predicate:
condition_vaiable.wait()
The some_predicate
tells you when something you care about has happened. But if you don't hold the lock when you check if some_predicate
is true then some other thread may have modified it in between the wait
returning and you checking the predicate. In addition you are generally waiting on a condition to be true in order to do something with a shared resource. For example, you might be waiting for a signal that a result is available and you should process it. But if that result isn't protected by a mutex it isn't safe to access it. You might think that if only 1 thread is notified that that object is ready then only 1 thread would process it but there's some issues with that:
- A mutex generally does more than just protect a resource; it also ensures that memory that was held in registers must be flushed to RAM so that it's visible to other CPUs where other threads might be running (this isn't such an issue for Python due to the GIL but in other languages it's very important).
- Compilers and CPUs can re-order instructions for efficiency but a mutex ensures that whatever happened before a mutex release in the code is actually executed before the mutex release in the optimized code and in the CPU pipeline.
- It's actually hard to ensure that exactly one thread is signaled by a
notify
so it's possible for more than one thread to be awakened (at least in some implementations) so you do, in fact, need to make sure that the mutex is held.