I'm a little confused because it seems to me that a coherent system could still allow for race conditions. That is, 'P0 write: 5' could have easily happened after 'P1 read' on a different program execution. Why is that? Are race conditions something that the programmer (and not the hardware) deals with?
Yes, a coherent memory system doesn't prevent race conditions. (If it did, we probably wouldn't have to worry about race conditions when writing programs.)
Instead, what a coherent system does is makes sure that any writes that any processor does to its local cache is "seen" by all the other processors. I think the definition of coherence means that memory behaves "properly" for every hypothetical execution order.
As we learn in the next lecture, how writes are "seen" by other processors depends on the memory consistency model. With a relaxed model, the read could occur before a write. With PC, one processor may have "seen" the value before another. Would this break the second part of this definition of coherence, since the read would not necessarily be the value of the last write to that location?
@jellybean I think one processor not yet seeing the write to a memory location performed by another processor doesn't violate coherence - coherence only guarantees a common serial ordering, not that there is only one serial ordering or that executing the program will always take the same ordering. For example, in lecture 13, slide 19 a cache coherent ordering associated with PC for memory address &A in the event that thread 3 prints "0" would be:
(1) Thread 3 reads A (reads 0);
(2) Thread 1 writes A (writes 1);
(3) Thread 2 reads A (reads 1).
(obviously skipping over some reads for concision). That ordering is consistent with the execution of the program and obeys the serial order of the program operations across all processors