Java の MCS Lock に対して、非常に奇妙なキャッシュ動作が発生します。基本的に、最大 4 つのスレッド (私のマシンのコアの数) で動作しますが、それ以上になるとスタックします。デバッグすると、プログラムが行で動かなくなっていることがわかります
while (qnode.locked);
lock() 関数の内部。デバッグ時に、スレッドの QNode の 1 つがロックされて false に設定されていることがわかりますが、これは、デバッガーがキャッシュを更新するためだと推測しています。必死の試みとして、すべての変数に「揮発性」を投げただけで無駄になりました。私が使用しているクラスは次のとおりです。
class MCSLock
{
private volatile AtomicReference<QNode> tail;
private volatile ThreadLocal<QNode> myNode;
public MCSLock()
{
tail = new AtomicReference<QNode>(null);
myNode = new ThreadLocal<QNode>()
{
protected QNode initialValue() { return new QNode(); }
};
}
public void lock()
{
QNode qnode = myNode.get();
QNode pred = tail.getAndSet(qnode);
if (pred != null)
{
qnode.locked = true;
pred.next = qnode;
while (qnode.locked);
}
}
public void unlock()
{
QNode qnode = myNode.get();
if (qnode.next == null)
{
if (tail.compareAndSet(qnode, null)) return;
while (qnode.next == null);
}
qnode.next.locked = false;
qnode.next = null;
}
private class QNode
{
volatile boolean locked = false;
volatile QNode next = null;
}
}