One of the big dangers with evaluating expressions that run code in the debugee is that the code you run might try to acquire some locked resource that is held by another thread in the program. That will cause the expression evaluation to deadlock.
One solution is to run the expression evaluation with a timeout, and if it takes too long, cancel the expression, clean up its stack and return an error. However, that can also be dangerous, for instance if the expression you run successfully acquires lock A, tries to get lock B, but that is held on another thread, so it deadlocks. If you cancel the expression evaluation at that point, you will leave lock A stranded, and your program going to grind to a halt as different threads all try to get that resource.
The obvious solution to this problem is to run all threads when you do, expression evaluation. However, that's not what most users want, they would find it disconcerting to have expression evaluation on one thread to cause some other thread to make progress.
lldb's solution to this problem is that when we run expressions, we first try running just the thread on which the expression is evaluated, but with some timeout (which is user settable.) If the expression evaluation times out on the one thread, and the "run_others" parameter to RunThreadPlan is passed in as true, we will interrupt the evaluation, and then restart with all threads running. So it is very possible that expression evaluation could cause another thread to get a chance to execute, which could in turn hit a breakpoint, or crash, or whatever else a thread might do while executing...
Short of the ability to track all locks in the system (a capability which most OS'es don't provide), this is the safest way around this problem. It will fail if the expression you are running tries to acquire a non-recursive lock held on the thread which runs the code. We could work around even that if we made up a debugger thread in the debugee for running expressions, though that would fail if any of the code in the expression tried to access thread specific data. I don't know whether it is possible to fake a thread's thread specific data so it looks like it belongs to another thread. If that's possible, we could probably make that work. OTOH, this particular problem doesn't seem to occur that often.
Anyway, again without being able to play around with the locks in a program directly, I can't see a way to run general expressions that might acquire locked resources without allowing all threads to run, at least as a fallback.