Advertisement
Nickpips

Untitled

Aug 1st, 2018
115
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 1.42 KB | None | 0 0
  1. This starts with lock1 = lock2 = lock3 = var = 1
  2. Note that "wait" is a spinlock waiting for the specific lock to be equal to 0.
  3.  
  4. Thread 1:
  5. wait(lock1)
  6. cmp lock3, 0 # lock3 should be zero, Thread 2 already ran.
  7. je end # Thus I take this path
  8. mov var, 0 # And this is never run
  9. end:
  10.  
  11. Thread 2:
  12. mov lock3, 0
  13. mov lock1, 0
  14. mov ebx, var # I should know that var is 1 here.
  15.  
  16. First, consider Thread 1:
  17. if `wait(lock1)` branch predicts that the lock isn't taken, it adds `cmp lock3, 0` to the pipeline
  18. In the pipeline, `cmp lock3, 0` reads lock3 and finds out that it equal to 1.
  19.  
  20. Now, assume Thread 1 is taking its sweet time, and Thread 2 begins running quickly:
  21. lock3 = 0
  22. lock1 = 0
  23.  
  24. Now, let's go back to Thread 1:
  25. Let's say the `wait(lock1)` reads lock1, finds out that lock1 is 0, and is happy about its branch predicting ability. This command commits, and nothing gets flushed
  26. (Correct branch predicting means nothing is flushed, even with out-of-order reads, since the processor deduced that there is no internal dependency. lock3 isn't dependent on lock1 in the eyes of the CPU, so this all is okay)
  27. (Hence why optimizing compilers will interleave consecutive independent for loops, so that they all get executed simultaneously)
  28. Now, the `cmp lock3, 0`, which correctly read that lock3 was equal to 1, commits. `je end` is not taken, and `mov var, 0` executes.
  29. In Thread 3, ebx is equal to 0. This should have been impossible.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement