Z3 Context Thread Safety Question #7762
Replies: 1 comment 1 reply
-
It isn't thread safe because z3_translate and related increment and decrement reference counts on ast nodes from the source context. I think you want to weigh the overhead of the broker against overhead of solving. Solving should be several orders of magnitude higher time and space overhead than replicating the ast nodes from the input. If ast node overhead is higher, then I am not sure it is useful to use threads in the first place. I use a broker in the local search solver to allow two threads to communicate information without being blocked on each other. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
This is sort of a follow-up to #4762. I've been working on the Rust z3 bindings and have been playing with a structured way to allow usages of the Rust API in multi-threaded scenarios (see prove-rs/z3.rs#404). From this investigation, I have a question about the thread-safety of the z3 context.
Background (feel free to skip)
My multi-threading strategy is this:
Context
s can never be moved to other threads or referenced by other threadsAst
s,Solver
s,Model
s, etc, may also never be moved or referenced across threads (I'm going to sayAst
for the rest of this, but I mean any of these types that isn't aContext
).Ast
s may be wrapped in a specialSendableHandle
structure:translate
s theAst
for a newContext
, owned by theSendableHandle
. No other code is able to see thisContext
.translate
is done, thisContext
is kept around for the lifetime of theSendableHandle
, and no further declarations are made inside it.SendableHandle
can be moved to another thread and then have its contents unwrapped and translated into anAst
associated with aContext
owned by the receiving thread through a call torecover(&ctx)
.This paradigm introduces some overhead, as
Ast
s must be translated twice, and there's an extraContext
construction/destruction every time something needs to move across threads, but it ensures that noAst
is ever accessed from a different thread than theContext
it is associated with, without relying on rust-side atomics or mutexes.So, my question comes because when I originally thought of this, I was thinking that the soundness of this approach required that
SendableHandle
could be moved to a thread but never referenced across threads. As an experiment I tried loosening these requirements and allowing references across threads. Much to my surprise, this worked.TLDR
So, my question is about the safety of the following pattern of interactions with the Z3 context. If I:
Context
Ast
/Solver
/etc in itContext
again outside of using it as the source ofZ3_translate
/Z3_solver_translate
/etc calls.Is it then safe to access the
Context
from other threads without synchronization?Beta Was this translation helpful? Give feedback.
All reactions