Questa è una variazione su CounterLatch
, disponibile dal sito Apache.
La loro versione, per ragioni a loro più note, blocca il thread del chiamante mentre la variabile (AtomicInteger
) ha un valore determinato.
Ma è l'altezza della facilità di modificare questo codice in modo che sia possibile scegliere solo la versione di Apache o ... "attendere qui fino al il contatore raggiunge un determinato valore". Probabilmente quest'ultimo avrà maggiore applicabilità. Nel mio caso particolare ho frastagliato questo perché volevo controllare che tutti i "pezzi" fossero stati pubblicati in SwingWorker.process()
... ma da allora ho trovato altri usi per questo.
Qui è scritto in Jython, ufficialmente la migliore lingua del mondo (TM). A un certo punto arriverò a dare una versione Java.
class CounterLatch():
def __init__(self, initial = 0, wait_value = 0, lift_on_reached = True):
self.count = java.util.concurrent.atomic.AtomicLong(initial)
self.signal = java.util.concurrent.atomic.AtomicLong(wait_value)
class Sync(java.util.concurrent.locks.AbstractQueuedSynchronizer):
def tryAcquireShared(sync_self, arg):
if lift_on_reached:
return -1 if ((not self.released.get()) and self.count.get() != self.signal.get()) else 1
else:
return -1 if ((not self.released.get()) and self.count.get() == self.signal.get()) else 1
def tryReleaseShared(self, args):
return True
self.sync = Sync()
self.released = java.util.concurrent.atomic.AtomicBoolean() # initialised at False
def await(self, *args):
if args:
assert len(args) == 2
assert type(args[ 0 ]) is int
timeout = args[ 0 ]
assert type(args[ 1 ]) is java.util.concurrent.TimeUnit
unit = args[ 1 ]
return self.sync.tryAcquireSharedNanos(1, unit.toNanos(timeout))
else:
self.sync.acquireSharedInterruptibly(1)
def count_relative(self, n):
previous = self.count.addAndGet(n)
if previous == self.signal.get():
self.sync.releaseShared(0)
return previous
NB la versione di Apache utilizza la parola chiave per volatile
signal
e released
. In Jython non penso che esista come tale, ma usando AtomicInteger
e AtomicBoolean
assicuriamo che nessun valore sia "non aggiornato" in nessun thread.
Esempio Utilizzo:
Nel costruttore SwingWorker:
self.publication_counter_latch = CounterLatch()
In SW.publish:
# increase counter value BEFORE publishing chunks
self.publication_counter_latch.count_relative(len(chunks))
self.super__publish(chunks)
In SW.process:
# ... do sthg [HERE] with the chunks!
# AFTER having done what you want to do with your chunks:
self.publication_counter_latch.count_relative(- len(chunks))
Nel thread in attesa dell'elaborazione del blocco t o di arresto:
worker.publication_counter_latch.await()
Sì, funzionerebbe. Ma vorrei qualcosa che non utilizza 2 oggetti di sincronizzazione per ottenere questo. Ne ho implementato uno usando LockSupport e sto attualmente testandolo per vedere se funziona e va bene (AQS non sembra essere buono neanche per questo). – Razvi
@ dead10ck perché no? – assylias