I think you're missing the point of a Condition: you have to check the condition predicate/variable inside the condition object, not outside.
The while point of condition.wait() is that it will wait until it's been notified. And it will wait cheaply, not using CPU power and burning down your battery; it does absolutely nothing until it's notified. So, if you use them properly, they do exactly what you ask: "wait for background thread only if the do_something() from background thread is not finished."
But you have to use them right. On the main thread, do this:
with condition:
condition.wait_for(is_flag_set)
do_stuff()
Then, on the background thread, you notify it like this:
do_something()
with condition:
set_flag()
condition.notify()
I've removed the timeout for simplicity. If you want to make sure that it waits until the background thread does do_something(), or 2 minutes, whichever comes sooner:
with condition:
if condition.wait_for(is_flag_set, 120):
do_stuff_after_flag_set()
else:
do_stuff_after_timeout()
Now, you're guaranteed that either do_stuff_after_flag_set gets called only after do_something finished on the background thread, or do_stuff_after_timeout gets called because the background thread took too long.
If you want to understand the problem with your (edited) existing code:
if not is_flag_set():
with condition:
condition.wait(120)
You're worried that the main thread can check the flag before the condition is set. Well, of course it can; you put the if before doing anything with the condition. That's why you have to use wait_for, or a while loop around wait, as in the example in the docs; it's the only way to be sure the flag is checked when you've been notified that it's ready to be checked.
Also, notice that you're not really synchronizing anything here. If the call to is_flag_set and set_flag don't happen inside the with condition:, the flag isn't synchronized between threads. (With CPython on most platforms, you will almost always get away with that, but if you're looking for what you can almost always get away with instead of what's correct, you really don't need a Condition in the first place…)
Some notes:
If you don't have Python 3.2 or later, you only have wait, not wait_for, and there's no way to tell whether the wait succeeded or timed out. Other than the timeout issue, c.wait_for(is_flag_set) is basically the same as while not is_flag_set(): c.wait(). So you can build wait_for yourself (notice that the docs link to the source), or you can find a backport on PyPI.
If you want to know why you need to do things this way, Wikipedia's Monitor article explains pretty nicely the problems that are solved by this extra complexity. (In the cases where you've thought through all the race conditions and know you don't need a Condition, use an Event instead.)
Notice that I used notify rather than notify_all (or notifyAll, which is another name for notify_all but has been deprecated since Python 2.6). If there's only one waiter, you only need to notify one waiter; it's simpler under the covers, and clearer about your intent. (If someone sees notify_all, they're liable to assume that you're using a thread pool, which you're not.)
Also notice that I put the do_stuff() inside the lock. This doesn't actually matter either way unless you're going to reset the flag and set it again later. But if it does, this protects you from "missed cycle" bugs.
Finally, it's not really true that you need a wait_for or a loop around wait; if the flag is only assigned once in the entire program, and the condition is only notified once, an if after the wait, instead of before as you tried, will have the same effect. (Then again, so will using an Event or other simpler sync object.) But it's better to just do it the safe way; then, you won't accidentally add races or deadlocks when you later edit something that doesn't seem related…
notifyAllhas been deprecated since Python 2.6; usenotify_all. But really, if you only have one waiter, why aren't you just usingnotify?