[mod] modified broadcastobject to mirror a real live broadcast better

- allow to watch until a specific or later frame has been cast
 - allow to return from watching if the broadcast is ended
 - allow to reset the broadcast to be reset
 - in retrospect this wasnt really needed for the project...
This commit is contained in:
2020-01-29 01:19:10 -06:00
parent 1e61253b3b
commit 5748b8272a

View File

@@ -35,6 +35,7 @@ object ScalaLocks {
} }
} }
// The conditional readlock waits for a condition to be met, before executing the provided read function
class ScalaConditionalReadLock(readLock: ReentrantReadWriteLock.ReadLock, writeLock: ReentrantReadWriteLock.WriteLock, signal: Condition) { class ScalaConditionalReadLock(readLock: ReentrantReadWriteLock.ReadLock, writeLock: ReentrantReadWriteLock.WriteLock, signal: Condition) {
private val scalaWriteLock = new ScalaWriteLock(writeLock) private val scalaWriteLock = new ScalaWriteLock(writeLock)
@@ -62,7 +63,7 @@ object ScalaLocks {
object ConcurrentBroadcast { object ConcurrentBroadcast {
class BroadcastObject[A]() { class BroadcastObject[A](default: Option[A] = None) {
import ScalaLocks._ import ScalaLocks._
@@ -76,12 +77,15 @@ object ConcurrentBroadcast {
private val writeLock = new ScalaWriteLock(javaWriteLock) private val writeLock = new ScalaWriteLock(javaWriteLock)
private val readLock = new ScalaReadLock(javaReadLock) private val readLock = new ScalaReadLock(javaReadLock)
private var value: Option[A] = None private var frame: Int = 0 // should be a large enough buffer
private var broadcastEnded = false
private var value: Option[A] = default
// NON-BLOCKING: check if value has been set, write new value and return if it was overwritten // NON-BLOCKING: check if value has been set, write new value and return if it was overwritten
def broadcast(newValue: A): Unit = { def broadcast(newValue: A): Unit = {
writeLock(() => { writeLock(() => {
value = Some(newValue) value = Some(newValue)
frame += 1
signal.signalAll() signal.signalAll()
}) })
} }
@@ -91,23 +95,62 @@ object ConcurrentBroadcast {
readWriteLock(() => { readWriteLock(() => {
val result = value.isEmpty val result = value.isEmpty
value = Some(newValue) value = Some(newValue)
frame += 1
signal.signalAll() signal.signalAll()
result result
}) })
} }
def broadcastStop(): Unit = {
writeLock(() => {
value = None // this indicates the watcher that the broadcast ended
broadcastEnded = true
signal.signal()
})
}
def broadcastRestart(): Unit = {
writeLock(() => {
broadcastEnded = false
})
}
def broadcastReset(): Unit = {
broadcastEnded = false
frame = 0
value = default
}
// BLOCKING: watch value, block until it is set, then return it // BLOCKING: watch value, block until it is set, then return it
def watch(): A = { def watch(): A = {
conditionalReadLock(!value.isEmpty, value.get) conditionalReadLock(!value.isEmpty, value.get)
} }
// BLOCKING: watch value, block until it is set or the broadcast ends
// returns None for broadcast end and Some[A] otherwise
def watchUntilEnd(): Option[A] = {
conditionalReadLock(!value.isEmpty || broadcastEnded, value)
}
// BLOCKING: watch value from frame, block until it is set, then return it
// IMPORTANT: no guarantee for the frame, a later one may be returned
def watchFrame(requestedFrame: Int): (A, Int) = {
conditionalReadLock(!value.isEmpty && frame >= requestedFrame, (value.get, frame))
}
// BLOCKING: watch value from frame, block until it is set or the broadcast ends
// returns None for broadcast end and Some[A] otherwise
// IMPORTANT: no guarantee for the frame, a later one may be returned
def watchFrameUntilEnd(requestedFrame: Int): (Option[A], Int) = {
conditionalReadLock((!value.isEmpty && frame >= requestedFrame) || broadcastEnded, (value, frame))
}
// NON-BLOCKING: returns value as Option // NON-BLOCKING: returns value as Option
def peak(): Option[A] = { def peak(): Option[A] = {
readLock { readLock {
value value
} }
} }
} }
abstract class Broadcast[A](stream: mutable.ArraySeq[BroadcastObject[A]]) extends Runnable { abstract class Broadcast[A](stream: mutable.ArraySeq[BroadcastObject[A]]) extends Runnable {