简体   繁体   中英

When should I think about Memory Barrier and Instruction Reorder?

I tried to implement Peterson Lock with C# like this

public class PetersonLock
{
    private volatile bool[] flag = new bool[2];
    private volatile int victim;
    public int oneThreadId;

    public void Lock() {
        int i = Thread.CurrentThread.ManagedThreadId == oneThreadId ? 1 : 0;
        int j = 1 - i;
        flag[i] = true; /* A */
        victim = i;     /* B */
        while (flag[j] && victim == i) { } /* C */
    }

    public void Unlock() {
        int i = Thread.CurrentThread.ManagedThreadId == oneThreadId ? 1 : 0;
        flag[i] = false;
    }
}

But when I use this lock in 2 threads, it didn't work, someone said I should think about Instruction Reorder and use Memory Barrier. Do Line A, Line B and Line C reorder like A->B->C, or A->C->B, or C->A->B or other orders? So I changed my code to this:

public class PetersonLock
{
    private volatile bool[] flag = new bool[2];
    private volatile int victim;
    public int oneThreadId;

    public void Lock() {
        int i = Thread.CurrentThread.ManagedThreadId == oneThreadId ? 1 : 0;
        int j = 1 - i;
        flag[i] = true;
        Thread.MemoryBarrier(); // Is this line nesscessary?
        victim = i;
        Thread.MemoryBarrier(); // Is this line nesscessary?
        while (flag[j] && victim == i) { }
    }

    public void Unlock() {
        int i = Thread.CurrentThread.ManagedThreadId == oneThreadId ? 1 : 0;
        flag[i] = false;
    }
}
  • I don't know whether these two lines are both nesscessary?
  • Is there any rules to help me judge which line WILL be reordered and which line WILL NOT be?
  • When should I use Memory Barrier?

According to Microsoft Documentation , there are simpler ways to synchronize code using locks and the Monitor class. If you still want to stick to Thread.MemoryBarrier , I found this link quite interesting.

Regarding your code, I'm not very familiar with the PetersonLock, so don't take my words blindly. I would say that the first barrier is used to ensure that flag is set before the victim is set and the second barrier is needed to flush the memory to all cached memory lines so all the threads read the same value

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM