Re: ThreadPoolExecutor backport





Lew a écrit :
Philipp wrote:


class PausableThreadPoolExecutor extends ThreadPoolExecutor {
private boolean isPaused;
private ReentrantLock pauseLock = new ReentrantLock();
private Condition unpaused = pauseLock.newCondition();

public PausableThreadPoolExecutor(...) { super(...);

protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
pauseLock.lock();
try {
while (isPaused) unpaused.await();
} catch (InterruptedException ie) {
t.interrupt();
} finally {
pauseLock.unlock();
}
}

public void pause() {
pauseLock.lock();
try {
isPaused = true;
} finally {
pauseLock.unlock();
}
}

public void resume() {
pauseLock.lock();
try {
isPaused = false;
unpaused.signalAll();
} finally {
pauseLock.unlock();
}
}
}}

Q: Why does the boolean flag isPaused need not be volatile?
As I see it, it will be polled and set by different threads and
nothing guarantees a memory barrier.

Nothing but the 'pauseLock.lock()', that is.

Thanks for your non-answer. It made me look harder.
Actually, the thing that happens is that in beforeExecute(),
unpaused.await() unlocks the acquired lock pauseLock. This then
(later) gets locked by resume() where signalAll awakes the waiting
thread in beforeExecute(). At this time, the waiting thread is awake,
but cannot execute because it must first reacquire the lock (which is
still held in resume() ). As soon as resume() releases the lock, it is
reacquired by beforeExecute(). Now what makes it all work without the
volatile keyword, is that the unlock() in resume() establishes a
happens-before relation with respect to a subsequent lock of
pauseLock. So the value of isPaused is updated as soon as the waiting
thread starts to run again.

Phil
.



Relevant Pages

  • Re: thread-safety
    ... and I started to use dotnet's queue collection with lock protection. ... private enum WorkerThreadState; ... private object stateLocker = new object; ... public void Start ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: thread-safety
    ... It supports immediate addition to the consumer's queue, and creation of a repeating timer that will periodicially add to the consumer's queue. ... private TimeSpan _tsExecute; ... // the JobConsumer class while holding it's own lock. ... public void Add ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: .net 2.0 : looking for a "best practice" for multi threading jobs
    ... private int m_numberOfThreads; ... private object m_numberOfThreadsLockObject = new object; ... lock ... public void AddAction ...
    (microsoft.public.dotnet.framework)
  • Re: SyncLock documentation
    ... You should declare a Private object variable to ... variable to protect data common to all instances. ... You should not use the Me keyword to provide a lock object for instance ... In the example below, bbb uses 'synclock me', and ccc uses 'synclock sss' ...
    (microsoft.public.dotnet.languages.vb)
  • Re: lock statement question
    ... I have a private timer member whose interval can be changed by different threads. ... When you lock on an object, it doesn't protect the object itself from access in any way, it only prevents other threads to enter any code that is locked using the same object. ... They use the same object for locking, so while some thread is using one of the methods, no other thread can use any of the two methods. ...
    (microsoft.public.dotnet.languages.csharp)