Reputation: 990
I'm getting some really odd cache behavior for an MCS Lock in Java. Basically, it will work for up to four threads (the number of cores on my machine), but will get stuck for more. When I debug, I see that the program is getting stuck on the line
while (qnode.locked);
Inside of the lock() function. When debugging, I can see that one of the thread's QNode has locked set to false, but I'm guessing that's because the debugger causes the cache to update. I just threw "volatile" onto all variables as a desperate attempt to no avail. Here's the class that I'm using:
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;
}
}
Upvotes: 1
Views: 477
Reputation: 11
I have got the same problem. There is a small error into unlock() method. Before setting the false value into locked variable for the next node we need to wait untill this value gets true into lock method. I added
while (!qnode.next.locked) {}
before
qnode.next.locked = false;
into unlock() method and the problem ran away!
Upvotes: 1
Reputation: 16
Your code works! However, my guess is that your system isn't good enough to do >4 threads quickly.
Running on a dual-core i5, execution hung on 5 threads
Running on a quad-core overclocked i7, execution completed on 5 threads as expected. Woo!
Upvotes: 0
Reputation: 612
while (qnode.locked);
doesn't do anything as far as i can see . Maybe you mean
do {
pred.next = qnode;
// update qnode
} while (qnode.locked);
Upvotes: 0