Thanks Dave. Adding following quote from Section 16.14.6 of LRM
Unlike an immediate assertion, a procedural concurrent assertion is not immediately evaluated when reached in procedural code.
Instead, the assertion and the current values of all constant and automatic expressions appearing in its assertion arguments (see 16.14.6.1)
are placed in a procedural assertion queue associated with the currently executing process.
Each of the entries in this queue is said to be a pending procedural assertion instance.
At T: 10ns, both p1 & p2 are placed in procedural assertion queue associated with their respective process i.e initial blocks I2 & I3 respectively.
LRM further states ::
In the Observed region of each simulation time step, each pending procedural assertion instance that is currently present in a procedural assertion queue shall mature, which means it is confirmed for execution.
When a pending procedural assertion instance matures, if the current time step is one that corresponds to that assertion instance’s leading clocking event, an evaluation attempt of the assertion begins immediately within the Observed region.
In the observed region of time 10ns both p1 & p2 are evaluated since the current time step corresponds to their leading clocking event (even though the clocking event has passed by then)
As a result, there is no race condition with procedural concurrent assertions