scala.collection.generic.Signalling.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scala-library Show documentation
Show all versions of scala-library Show documentation
Standard library for the Scala Programming Language
/* __ *\
** ________ ___ / / ___ Scala API **
** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
** /____/\___/_/ |_/____/_/ | | **
** |/ **
\* */
package scala.collection.generic
import java.util.concurrent.atomic.AtomicInteger
/**
* A message interface serves as a unique interface to the
* part of the collection capable of receiving messages from
* a different task.
*
* One example of use of this is the `find` method, which can use the
* signalling interface to inform worker threads that an element has
* been found and no further search is necessary.
*
* @author prokopec
*
* @define abortflag
* Abort flag being true means that a worker can abort and produce whatever result,
* since its result will not affect the final result of computation. An example
* of operations using this are `find`, `forall` and `exists` methods.
*
* @define indexflag
* The index flag holds an integer which carries some operation-specific meaning. For
* instance, `takeWhile` operation sets the index flag to the position of the element
* where the predicate fails. Other workers may check this index against the indices
* they are working on and return if this index is smaller than their index. Examples
* of operations using this are `takeWhile`, `dropWhile`, `span` and `indexOf`.
*/
trait Signalling {
/**
* Checks whether an abort signal has been issued.
*
* $abortflag
* @return the state of the abort
*/
def isAborted: Boolean
/**
* Sends an abort signal to other workers.
*
* $abortflag
*/
def abort(): Unit
/**
* Returns the value of the index flag.
*
* $indexflag
* @return the value of the index flag
*/
def indexFlag: Int
/**
* Sets the value of the index flag.
*
* $indexflag
* @param f the value to which the index flag is set.
*/
def setIndexFlag(f: Int)
/**
* Sets the value of the index flag if argument is greater than current value.
* This method does this atomically.
*
* $indexflag
* @param f the value to which the index flag is set
*/
def setIndexFlagIfGreater(f: Int)
/**
* Sets the value of the index flag if argument is lesser than current value.
* This method does this atomically.
*
* $indexflag
* @param f the value to which the index flag is set
*/
def setIndexFlagIfLesser(f: Int)
/**
* A read only tag specific to the signalling object. It is used to give
* specific workers information on the part of the collection being operated on.
*/
def tag: Int
}
/**
* This signalling implementation returns default values and ignores received signals.
*/
class DefaultSignalling extends Signalling with VolatileAbort {
def indexFlag = -1
def setIndexFlag(f: Int) {}
def setIndexFlagIfGreater(f: Int) {}
def setIndexFlagIfLesser(f: Int) {}
def tag = -1
}
/**
* An object that returns default values and ignores received signals.
*/
object IdleSignalling extends DefaultSignalling
/**
* A mixin trait that implements abort flag behaviour using volatile variables.
*/
trait VolatileAbort extends Signalling {
@volatile private var abortflag = false
override def isAborted = abortflag
override def abort() = abortflag = true
}
/**
* A mixin trait that implements index flag behaviour using atomic integers.
* The `setIndex` operation is wait-free, while conditional set operations `setIndexIfGreater`
* and `setIndexIfLesser` are lock-free and support only monotonic changes.
*/
trait AtomicIndexFlag extends Signalling {
private val intflag: AtomicInteger = new AtomicInteger(-1)
abstract override def indexFlag = intflag.get
abstract override def setIndexFlag(f: Int) = intflag.set(f)
abstract override def setIndexFlagIfGreater(f: Int) = {
var loop = true
do {
val old = intflag.get
if (f <= old) loop = false
else if (intflag.compareAndSet(old, f)) loop = false
} while (loop);
}
abstract override def setIndexFlagIfLesser(f: Int) = {
var loop = true
do {
val old = intflag.get
if (f >= old) loop = false
else if (intflag.compareAndSet(old, f)) loop = false
} while (loop);
}
}
/**
* An implementation of the signalling interface using delegates.
*/
trait DelegatedSignalling extends Signalling {
/**
* A delegate that method calls are redirected to.
*/
var signalDelegate: Signalling
def isAborted = signalDelegate.isAborted
def abort() = signalDelegate.abort
def indexFlag = signalDelegate.indexFlag
def setIndexFlag(f: Int) = signalDelegate.setIndexFlag(f)
def setIndexFlagIfGreater(f: Int) = signalDelegate.setIndexFlagIfGreater(f)
def setIndexFlagIfLesser(f: Int) = signalDelegate.setIndexFlagIfLesser(f)
def tag = signalDelegate.tag
}
/**
* Class implementing delegated signalling.
*/
class DelegatedContext(var signalDelegate: Signalling) extends DelegatedSignalling
/**
* Class implementing delegated signalling, but having its own distinct `tag`.
*/
class TaggedDelegatedContext(deleg: Signalling, override val tag: Int) extends DelegatedContext(deleg)