A predicate transformer approach to semantics of parallel programs