如何解决我什么时候应该考虑内存屏障和指令重新排序?
我尝试像这样用 C# 实现 Peterson Lock
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;
}
}
但是当我在 2 个线程中使用这个锁时,它不起作用,有人说我应该考虑指令重新排序并使用内存屏障。 A线、B线和C线是否像A->B->C,或A->C->B,或C->A->B或其他顺序一样重新排序?所以我把我的代码改成这样:
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;
}
}
- 不知道这两行是不是都需要?
- 有什么规则可以帮助我判断哪一行会被重新排序,哪一行会被重新排序? 行不会?
- 我应该什么时候使用内存屏障?
解决方法
根据Microsoft Documentation,有更简单的方法可以使用锁和Monitor 类来同步代码。
如果您仍想坚持使用 Thread.MemoryBarrier
,我发现这个 link 非常有趣。
关于你的代码,我对 PetersonLock 不是很熟悉,所以不要盲目相信我的话。我会说第一个屏障用于确保在设置受害者之前设置标志,并且需要第二个屏障将内存刷新到所有缓存的内存行,以便所有线程读取相同的值
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。