1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-08 17:45:24 +02:00

Make Mutex thread-safe by doing IProgressMonitor queries outside synchronized

This commit is contained in:
Martin Oberhuber 2006-08-16 13:14:48 +00:00
parent e892da770b
commit d40a6c11ff

View file

@ -55,58 +55,72 @@ public class Mutex {
* @param timeout Maximum wait time given in milliseconds. * @param timeout Maximum wait time given in milliseconds.
* @return <code>true</code> if the lock was obtained successfully. * @return <code>true</code> if the lock was obtained successfully.
*/ */
public synchronized boolean waitForLock(IProgressMonitor monitor, long timeout) { public boolean waitForLock(IProgressMonitor monitor, long timeout) {
if (Thread.interrupted()) { if (Thread.interrupted()) {
return false; return false;
} }
if (fLocked) { final Thread myself = Thread.currentThread();
//need to wait for the lock. synchronized(fWaitQueue) {
boolean canceled = false; if (!fLocked) {
final Thread myself = Thread.currentThread(); //acquire the lock immediately.
try { fLocked = true;
fWaitQueue.add(myself); return true;
} else {
fWaitQueue.add(myself);
Activator.trace("Mutex: added "+myself+", size="+fWaitQueue.size()); //$NON-NLS-1$ //$NON-NLS-2$ Activator.trace("Mutex: added "+myself+", size="+fWaitQueue.size()); //$NON-NLS-1$ //$NON-NLS-2$
long start = System.currentTimeMillis();
long timeLeft = timeout;
long pollTime = (monitor!=null) ? 1000 : timeLeft;
long nextProgressUpdate = start+500;
while (timeLeft>0 && !canceled) {
try {
wait(timeLeft > pollTime ? pollTime : timeLeft);
Activator.trace("Mutex: wakeup "+myself+" ?"); //$NON-NLS-1$ //$NON-NLS-2$
//I'm still in the list, nobody is allowed to take me out!
//assert !fWaitQueue.isEmpty();
if (!fLocked && fWaitQueue.get(0) == myself) {
break; //gee it's my turn!
}
long curTime = System.currentTimeMillis();
timeLeft = start + timeout - curTime;
if (monitor!=null) {
//TODO put the calls to the progress monitor out
//of the synchronized{}
canceled = monitor.isCanceled();
if (!canceled && (curTime>nextProgressUpdate)) {
monitor.worked(1);
nextProgressUpdate+=1000;
}
}
} catch(InterruptedException e) {
canceled = true;
}
}
} finally {
fWaitQueue.remove(myself);
Activator.trace("Mutex: removed "+myself+", size="+fWaitQueue.size()); //$NON-NLS-1$ //$NON-NLS-2$
}
if (fLocked || canceled) {
//we were not able to acquire the lock due to an exception,
//or because the wait was canceled.
return false;
} }
} }
//acquire the lock myself now. //need to wait for the lock.
fLocked = true; boolean lockAcquired = false;
return true; try {
long start = System.currentTimeMillis();
long timeLeft = timeout;
long pollTime = (monitor!=null) ? 1000 : timeLeft;
long nextProgressUpdate = start+500;
boolean canceled = false;
while (timeLeft>0 && !canceled && !lockAcquired) {
//is it my turn yet? Check wait queue and wait
synchronized(fWaitQueue) {
if (!fLocked && fWaitQueue.get(0) == myself) {
fWaitQueue.remove(0);
Activator.trace("Mutex: SUCCESS, removed "+myself+", size="+fWaitQueue.size()); //$NON-NLS-1$ //$NON-NLS-2$
fLocked = true;
lockAcquired = true;
} else {
fWaitQueue.wait(timeLeft > pollTime ? pollTime : timeLeft);
if (!fLocked && fWaitQueue.get(0) == myself) {
fWaitQueue.remove(0);
Activator.trace("Mutex: SUCCESS, removed "+myself+", size="+fWaitQueue.size()); //$NON-NLS-1$ //$NON-NLS-2$
fLocked = true;
lockAcquired = true;
}
}
}
if (!lockAcquired) {
//Need to continue waiting
Activator.trace("Mutex: wakeup "+myself+" ?"); //$NON-NLS-1$ //$NON-NLS-2$
long curTime = System.currentTimeMillis();
timeLeft = start + timeout - curTime;
if (monitor!=null) {
canceled = monitor.isCanceled();
if (!canceled && (curTime>nextProgressUpdate)) {
monitor.worked(1);
nextProgressUpdate+=1000;
}
}
}
}
} catch(InterruptedException e) {
//canceled waiting -> no lock aquired
} finally {
if (!lockAcquired) {
synchronized(fWaitQueue) {
fWaitQueue.remove(myself);
Activator.trace("Mutex: FAIL, removed "+myself+", size="+fWaitQueue.size()); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
return lockAcquired;
} }
/** /**
@ -115,12 +129,14 @@ public class Mutex {
* May only be called by the same thread that originally acquired * May only be called by the same thread that originally acquired
* the Mutex. * the Mutex.
*/ */
public synchronized void release() { public void release() {
fLocked=false; synchronized(fWaitQueue) {
if (!fWaitQueue.isEmpty()) { fLocked=false;
Object nextOneInQueue = fWaitQueue.get(0); if (!fWaitQueue.isEmpty()) {
Activator.trace("Mutex: releasing "+nextOneInQueue); //$NON-NLS-1$ Object nextOneInQueue = fWaitQueue.get(0);
notifyAll(); Activator.trace("Mutex: releasing "+nextOneInQueue); //$NON-NLS-1$
fWaitQueue.notifyAll();
}
} }
} }
@ -128,8 +144,10 @@ public class Mutex {
* Return this Mutex's lock status. * Return this Mutex's lock status.
* @return <code>true</code> if this mutex is currently acquired by a thread. * @return <code>true</code> if this mutex is currently acquired by a thread.
*/ */
public synchronized boolean isLocked() { public boolean isLocked() {
return fLocked; synchronized(fWaitQueue) {
return fLocked;
}
} }
/** /**
@ -139,11 +157,13 @@ public class Mutex {
* This should be called if the resource that the Threads are * This should be called if the resource that the Threads are
* contending for, becomes unavailable for some other reason. * contending for, becomes unavailable for some other reason.
*/ */
public synchronized void interruptAll() { public void interruptAll() {
Iterator it = fWaitQueue.iterator(); synchronized(fWaitQueue) {
while (it.hasNext()) { Iterator it = fWaitQueue.iterator();
Thread aThread = (Thread)it.next(); while (it.hasNext()) {
aThread.interrupt(); Thread aThread = (Thread)it.next();
aThread.interrupt();
}
} }
} }