Cartesian abstraction and verification of multithreaded programs