"The Pentium 4, Intel Xeon, P6 family, Pentium, and Intel486 processors guarantee that the following basic memory operations will always be carried out atomically: reading or writing a byte, reading or writing a word aligned on a 16-bit boundary, and reading or writing a doubleword aligned on a 32-bit boundary.
"The Pentium 4, Intel Xeon, and P6 family, and Pentium processors guarantee that the following additional memory operations will always be carried out atomically: reading or writing a quadword aligned on a 64-bit boundary."
Numerous methods exists for ensuring data consistency. To motivate the discussion, consider this simple (and wrong) algorithm for allocating a token that signifies permission to modify shared data:
int token = 0; A: if (token == 0) { /* no one has it */ B: token = 1; /* now I have it */ /* modify shared data here */ token = 0; /* now I give it up */ } else { /* I didn't get it; I'll try again */ }Why is this wrong?
Suppose token is 0 (unclaimed), and Process 1 (P1) executes line A and gets to line B. At this point, P1 can be swapped out, and P2 can run. Now, P2 executes its line A, sees that token is still 0, and gets to its line B. At this point, P1 and P2 will set token to 1, but it's too late: both think they have the token. This technique will not work.
Brief explanations of some techniques that do work are given below. See [TAN] or [DEI] for a textbook treatment.
int favored_process = 0; int p0_wants_to_enter = 0; int p1_wants_to_enter = 0; /* how p0 gets the resource */ p0_wants_to_enter = 1; favored_process = 1; while (p1_wants_to_enter && favored_process == 1) /* spinlock */ ; /* operate on shared resource here */ p0_wants_to_enter = 0; /* give up the resource */ /* how p1 gets the resource */ p1_wants_to_enter = 1; favored_process = 0; while (p0_wants_to_enter && favored_process == 0) /* spinlock */ ; /* operate on shared resource here */ p1_wants_to_enter = 0; /* give up the resource */
value = 1; xchg(&flag, &value);After the 'xchg()' call, 'value' is what 'flag' was, and 'flag' is 1. If 'value' becomes 0, this means that 'flag' was 0, the caller now has the resource, and the flag is set to 1 to block others. If 'value' remains 1, this means that 'flag' was 1, and the caller does not have the resource (setting a 1 flag to 1 does no harm).
struct mystruct { char head; int data[1000]; char tail; };