Memory Consistency Models: A Tutorial