org.scalatest.concurrent

# Conductor

#### class Conductor extends AnyRef

Class that facilitates the testing of classes, traits, and libraries designed to be used by multiple threads concurrently.

A `Conductor` conducts a multi-threaded scenario by maintaining a clock of "beats." Beats are numbered starting with 0. You can ask a`Conductor` to run threads that interact with the class, trait, or library (the subject) you want to test. A thread can call the `Conductor`'s`waitForBeat` method, which will cause the thread to block until that beat has been reached. The `Conductor` will advance the beat only when all threads participating in the test are blocked. By tying the timing of thread activities to specific beats, you can write tests for concurrent systems that have deterministic interleavings of threads.

A `Conductor` object has a three-phase lifecycle. It begins its life in the setup phase. During this phase, you can start threads by invoking the `thread` method on the `Conductor`. When `conduct` is invoked on a `Conductor`, it enters the conducting phase. During this phase it conducts the one multi-threaded scenario it was designed to conduct. After all participating threads have exited, either by returning normally or throwing an exception, the `conduct` method will complete, either by returning normally or throwing an exception. As soon as the `conduct` method completes, the `Conductor`enters its defunct phase. Once the `Conductor` has conducted a multi-threaded scenario, it is defunct and can't be reused. To run the same test again, you'll need to create a new instance of `Conductor`.

Here's an example of the use of `Conductor` to test the `ArrayBlockingQueue`class from `java.util.concurrent`:

    import org.scalatest.fixture.FunSuite
    import org.scalatest.matchers.ShouldMatchers
    import java.util.concurrent.ArrayBlockingQueueclass ArrayBlockingQueueSuite extends FunSuite with ShouldMatchers {  test("calling put on a full queue blocks the producer thread") {    val conductor = new Conductor
        import conductor._    val buf = new ArrayBlockingQueue[Int](1)    thread("producer") {
          buf put 42
          buf put 17
          beat should be (1)
        }    thread("consumer") {
          waitForBeat(1)
          buf.take should be (42)
          buf.take should be (17)
        }    whenFinished {
          buf should be ('empty)
        }
      }
    }

When the test shown is run, it will create one thread named producer and another namedconsumer. The producer thread will eventually execute the code passed as a by-name parameter to `thread("producer")`:

    buf put 42
    buf put 17
    beat should be (1)

Similarly, the consumer thread will eventually execute the code passed as a by-name parameter to `thread("consumer")`:

    waitForBeat(1)
    buf.take should be (42)
    buf.take should be (17)

The `thread` calls create the threads and starts them, but they will not immediately execute the by-name parameter passed to them. They will first block, waiting for the `Conductor`to give them a green light to proceed.

The next call in the test is `whenFinished`. This method will first call `conduct` on the `Conductor`, which will wait until all threads that were created (in this case, producer and consumer) are at the "starting line", i.e., they have all started and are blocked, waiting on the green light. The `conduct` method will then give these threads the green light and they will all start executing their blocks concurrently.

When the threads are given the green light, the beat is 0. The first thing the producer thread does is put 42 in into the queue. As the queue is empty at this point, this succeeds. The producer thread next attempts to put a 17 into the queue, but because the queue has size 1, this can't succeed until the consumer thread has read the 42 from the queue. This hasn't happened yet, so producer blocks. Meanwhile, the consumer thread's first act is to call `waitForBeat(1)`. Because the beat starts out at 0, this call will block the consumer thread. As a result, once the producer thread has executed `buf put 17` and the consumer thread has executed`waitForBeat(1)`, both threads will be blocked.

The `Conductor` maintains a clock that wakes up periodically and checks to see if all threads participating in the multi-threaded scenario (in this case, producer and consumer) are blocked. If so, it increments the beat. Thus sometime later the beat will be incremented, from 0 to 1. Because consumer was waiting for beat 1, it will wake up (i.e., the `waitForBeat(1)` call will return) and execute the next line of code in its block, `buf.take should be (42)`. This will succeed, because the producer thread had previously (during beat 0) put 42 into the queue. This act will also make producer runnable again, because it was blocked on the second `put`, which was waiting for another thread to read that 42.

Now both threads are unblocked and able to execute their next statement. The order is non-deterministic, and can even be simultaneous if running on multiple cores. If the `consumer` thread happens to execute `buf.take should be (17)` first, it will block (`buf.take` will not return), because the queue is at that point empty. At some point later, the producer thread will execute `buf put 17`, which will unblock the consumer thread. Again both threads will be runnable and the order non-deterministic and possibly simulataneous. The producer thread may charge ahead and run its next statement, `beat should be (1)`. This will succeed because the beat is indeed 1 at this point. As this is the last statement in the producer's block, the producer thread will exit normally (it won't throw an exception). At some point later the consumer thread will be allowed to complete its last statement, the `buf.take` call will return 17. The consumer thread will execute `17 should be (17)`. This will succeed and as this was the last statement in its block, the consumer will return normally.

If either the producer or consumer thread had completed abruptbly with an exception, the `conduct` method (which was called by `whenFinished`) would have completed abruptly with an exception to indicate the test failed. However, since both threads returned normally, `conduct` will return. Because `conduct` doesn't throw an exception, `whenFinished` will execute the block of code passed as a by-name parameter to it: `buf should be ('empty)`. This will succeed, because the queue is indeed empty at this point. The `whenFinished` method will then return, and because the `whenFinished` call was the last statement in the test and it didn't throw an exception, the test completes successfully.

This test tests `ArrayBlockingQueue`, to make sure it works as expected. If there were a bug in `ArrayBlockingQueue`such as a `put` called on a full queue didn't block, but instead overwrote the previous value, this test would detect it. However, if there were a bug in `ArrayBlockingQueue` such that a call to `take` called on an empty queue never blocked and always returned 0, this test might not detect it. The reason is that whether the consumer thread will ever call`take` on an empty queue during this test is non-deterministic. It depends on how the threads get scheduled during beat 1. What is deterministic in this test, because the consumer thread blocks during beat 0, is that the producer thread will definitely attempt to write to a full queue. To make sure the other scenario is tested, you'd need a different test:

    test("calling take on an empty queue blocks the consumer thread") {  val conductor = new Conductor
      import conductor._  val buf = new ArrayBlockingQueue[Int](1)  thread("producer") {
        waitForBeat(1)
        buf put 42
        buf put 17
      }  thread("consumer") {
        buf.take should be (42)
        buf.take should be (17)
        beat should be (1)
      }  whenFinished {
        buf should be ('empty)
      }
    }

In this test, the producer thread will block, waiting for beat 1. The consumer thread will invoke `buf.take`as its first act. This will block, because the queue is empty. Because both threads are blocked, the `Conductor`will at some point later increment the beat to 1. This will awaken the producer thread. It will return from its`waitForBeat(1)` call and execute `buf put 42`. This will unblock the consumer thread, which will take the 42, and so on.

The problem that `Conductor` is designed to address is the difficulty, caused by the non-deterministic nature of thread scheduling, of testing classes, traits, and libraries that are intended to be used by multiple threads. If you just create a test in which one thread reads from an `ArrayBlockingQueue` and another writes to it, you can't be sure that you have tested all possible interleavings of threads, no matter how many times you run the test. The purpose of `Conductor`is to enable you to write tests with deterministic interleavings of threads. If you write one test for each possible interleaving of threads, then you can be sure you have all the scenarios tested. The two tests shown here, for example, ensure that both the scenario in which a producer thread tries to write to a full queue and the scenario in which a consumer thread tries to take from an empty queue are tested.

Class `Conductor` was inspired by theMultithreadedTC project, created by Bill Pugh and Nat Ayewah of the University of Maryland.

Although useful, bear in mind that a `Conductor`'s results are not guaranteed to be accurate 100% of the time. The reason is that it uses `java.lang.Thread`'s `getState` method to decide when to advance the beat. This kind of use is advised against in the Javadoc documentation for`getState`, which says, "This method is designed for use in monitoring of the system state, not for synchronization." In short, sometimes the return value of <code>getState</code may be inacurrate, which in turn means that sometimes a `Conductor` may decide to advance the beat too early.

attributes: final
linear super types: AnyRef, Any
Ordering

1. Alphabetic
2. By inheritance

Inherited

1. Hide All
2. Show all

1. Conductor
2. AnyRef
3. Any

Visibility

1. Public
2. All

Impl.

1. Concrete
2. Abstract

### Instance constructors

1. #### new Conductor ()

### Value Members

1. #### def != (arg0: AnyRef) : Boolean

   attributes: final
   definition classes: AnyRef

2. #### def != (arg0: Any) : Boolean

   `o != arg0` is the same as `!(o == (arg0))`.

   `o != arg0` is the same as `!(o == (arg0))`.

   arg0

     the object to compare against this object for dis-equality.

   returns

     `false` if the receiver object is equivalent to the argument; `true` otherwise.

   attributes: final
   definition classes: Any

3. #### def ## () : Int

   attributes: final
   definition classes: AnyRef → Any

4. #### def $asInstanceOf [T0] () : T0

   attributes: final
   definition classes: AnyRef

5. #### def $isInstanceOf [T0] () : Boolean

   attributes: final
   definition classes: AnyRef

6. #### def == (arg0: AnyRef) : Boolean

   `o == arg0` is the same as `if (o eq null) arg0 eq null else o.equals(arg0)`.

   `o == arg0` is the same as `if (o eq null) arg0 eq null else o.equals(arg0)`.

   arg0

     the object to compare against this object for equality.

   returns

     `true` if the receiver object is equivalent to the argument; `false` otherwise.

   attributes: final
   definition classes: AnyRef

7. #### def == (arg0: Any) : Boolean

   `o == arg0` is the same as `o.equals(arg0)`.

   `o == arg0` is the same as `o.equals(arg0)`.

   arg0

     the object to compare against this object for equality.

   returns

     `true` if the receiver object is equivalent to the argument; `false` otherwise.

   attributes: final
   definition classes: Any

8. #### def asInstanceOf [T0] : T0

   This method is used to cast the receiver object to be of type `T0`.

   This method is used to cast the receiver object to be of type `T0`.

   Note that the success of a cast at runtime is modulo Scala's erasure semantics. Therefore the expression`1.asInstanceOf[String]` will throw a `ClassCastException` at runtime, while the expression`List(1).asInstanceOf[List[String]]` will not. In the latter example, because the type argument is erased as part of compilation it is not possible to check whether the contents of the list are of the requested typed.

   returns

     the receiver object.

   attributes: final
   definition classes: Any

9. #### def beat : Int

   The current value of the thread clock.

   The current value of the thread clock.

   returns

     the current beat value

10. #### def clone () : AnyRef

    This method creates and returns a copy of the receiver object.

    This method creates and returns a copy of the receiver object.

    The default implementation of the `clone` method is platform dependent.

    returns

      a copy of the receiver object.

    attributes: protected
    definition classes: AnyRef

11. #### def conduct (clockPeriod: Int, timeout: Int) : Unit

    Conducts a multithreaded test with the specified clock period (in milliseconds) and timeout (in seconds).

    Conducts a multithreaded test with the specified clock period (in milliseconds) and timeout (in seconds).

    A `Conductor` instance maintains an internal clock, which will wake up periodically and check to see if it should advance the beat, abort the test, or go back to sleep. It sleeps `clockPeriod` milliseconds each time. It will abort the test if either deadlock is suspected or the beat has not advanced for the number of seconds specified as `timeout`. Suspected deadlock will be declared if for some number of consecutive clock cycles, all test threads are in the `BLOCKED` or`WAITING` states and none of them are waiting for a beat.

    clockPeriod

      The period (in ms) the clock will sleep each time it sleeps

    timeout

      The maximum allowed time between successive advances of the beat. If this time is exceeded, the Conductor will abort the test.

12. #### def conduct () : Unit

    Conducts a multithreaded test with a default clock period of 10 milliseconds and default run limit of 5 seconds.

    Conducts a multithreaded test with a default clock period of 10 milliseconds and default run limit of 5 seconds.

13. #### def conductingHasBegun : Boolean

    Indicates whether either of the two overloaded `conduct` methods have been invoked.

    Indicates whether either of the two overloaded `conduct` methods have been invoked.

    This method returns true if either `conduct` method has been invoked. The`conduct` method may have returned or not. (In other words, a `true`result from this method does not mean the `conduct` method has returned, just that it was already been invoked and,therefore, the multi-threaded scenario it conducts has definitely begun.)

14. #### def eq (arg0: AnyRef) : Boolean

    This method is used to test whether the argument (`arg0`) is a reference to the receiver object (`this`).

    This method is used to test whether the argument (`arg0`) is a reference to the receiver object (`this`).

    The `eq` method implements an [http://en.wikipedia.org/wiki/Equivalence_relation equivalence relation] on non-null instances of `AnyRef`: * It is reflexive: for any non-null instance `x` of type `AnyRef`, `x.eq(x)` returns `true`. * It is symmetric: for any non-null instances `x` and `y` of type `AnyRef`, `x.eq(y)` returns `true` if and only if `y.eq(x)` returns `true`. * It is transitive: for any non-null instances `x`, `y`, and `z` of type `AnyRef` if `x.eq(y)` returns `true` and `y.eq(z)` returns `true`, then `x.eq(z)` returns `true`.

    Additionally, the `eq` method has three other properties. * It is consistent: for any non-null instances `x` and `y` of type `AnyRef`, multiple invocations of `x.eq(y)` consistently returns `true` or consistently returns `false`. * For any non-null instance `x` of type `AnyRef`, `x.eq(null)` and `null.eq(x)` returns `false`. * `null.eq(null)` returns `true`.

    When overriding the `equals` or `hashCode` methods, it is important to ensure that their behavior is consistent with reference equality. Therefore, if two objects are references to each other (`o1 eq o2`), they should be equal to each other (`o1 == o2`) and they should hash to the same value (`o1.hashCode == o2.hashCode`).

    arg0

      the object to compare against this object for reference equality.

    returns

      `true` if the argument is a reference to the receiver object; `false` otherwise.

    attributes: final
    definition classes: AnyRef

15. #### def equals (arg0: Any) : Boolean

    This method is used to compare the receiver object (`this`) with the argument object (`arg0`) for equivalence.

    This method is used to compare the receiver object (`this`) with the argument object (`arg0`) for equivalence.

    The default implementations of this method is an [http://en.wikipedia.org/wiki/Equivalence_relation equivalence relation]: * It is reflexive: for any instance `x` of type `Any`, `x.equals(x)` should return `true`. * It is symmetric: for any instances `x` and `y` of type `Any`, `x.equals(y)` should return `true` if and only if `y.equals(x)` returns `true`. * It is transitive: for any instances `x`, `y`, and `z` of type `AnyRef` if `x.equals(y)` returns `true` and `y.equals(z)` returns `true`, then `x.equals(z)` should return `true`.

    If you override this method, you should verify that your implementation remains an equivalence relation. Additionally, when overriding this method it is often necessary to override `hashCode` to ensure that objects that are "equal" (`o1.equals(o2)` returns `true`) hash to the same scala.Int (`o1.hashCode.equals(o2.hashCode)`).

    arg0

      the object to compare against this object for equality.

    returns

      `true` if the receiver object is equivalent to the argument; `false` otherwise.

    definition classes: AnyRef → Any

16. #### def finalize () : Unit

    This method is called by the garbage collector on the receiver object when garbage collection determines that there are no more references to the object.

    This method is called by the garbage collector on the receiver object when garbage collection determines that there are no more references to the object.

    The details of when and if the `finalize` method are invoked, as well as the interaction between `finalize`and non-local returns and exceptions, are all platform dependent.

    attributes: protected
    definition classes: AnyRef

17. #### def getClass () : java.lang.Class[_]

    Returns a representation that corresponds to the dynamic class of the receiver object.

    Returns a representation that corresponds to the dynamic class of the receiver object.

    The nature of the representation is platform dependent.

    returns

      a representation that corresponds to the dynamic class of the receiver object.

    attributes: final
    definition classes: AnyRef

18. #### def hashCode () : Int

    Returns a hash code value for the object.

    Returns a hash code value for the object.

    The default hashing algorithm is platform dependent.

    Note that it is allowed for two objects to have identical hash codes (`o1.hashCode.equals(o2.hashCode)`) yet not be equal (`o1.equals(o2)` returns `false`). A degenerate implementation could always return `0`. However, it is required that if two objects are equal (`o1.equals(o2)` returns `true`) that they have identical hash codes (`o1.hashCode.equals(o2.hashCode)`). Therefore, when overriding this method, be sure to verify that the behavior is consistent with the `equals` method.

    returns

      the hash code value for the object.

    definition classes: AnyRef → Any

19. #### def isConductorFrozen : Boolean

    Indicates whether the conductor has been frozen.

    Indicates whether the conductor has been frozen.

    Note: The only way a thread can freeze the conductor is by calling `withConductorFrozen`.

20. #### def isInstanceOf [T0] : Boolean

    This method is used to test whether the dynamic type of the receiver object is `T0`.

    This method is used to test whether the dynamic type of the receiver object is `T0`.

    Note that the test result of the test is modulo Scala's erasure semantics. Therefore the expression`1.isInstanceOf[String]` will return `false`, while the expression `List(1).isInstanceOf[List[String]]` will return `true`. In the latter example, because the type argument is erased as part of compilation it is not possible to check whether the contents of the list are of the requested typed.

    returns

      `true` if the receiver object is an instance of erasure of type `T0`; `false` otherwise.

    attributes: final
    definition classes: Any

21. #### def ne (arg0: AnyRef) : Boolean

    `o.ne(arg0)` is the same as `!(o.eq(arg0))`.

    `o.ne(arg0)` is the same as `!(o.eq(arg0))`.

    arg0

      the object to compare against this object for reference dis-equality.

    returns

      `false` if the argument is not a reference to the receiver object; `true` otherwise.

    attributes: final
    definition classes: AnyRef

22. #### def notify () : Unit

    Wakes up a single thread that is waiting on the receiver object's monitor.

    Wakes up a single thread that is waiting on the receiver object's monitor.

    attributes: final
    definition classes: AnyRef

23. #### def notifyAll () : Unit

    Wakes up all threads that are waiting on the receiver object's monitor.

    Wakes up all threads that are waiting on the receiver object's monitor.

    attributes: final
    definition classes: AnyRef

24. #### def synchronized [T0] (arg0: T0) : T0

    attributes: final
    definition classes: AnyRef

25. #### def thread (name: String)(fun: ⇒ Unit) : Thread

    Creates a new thread with the specified name that will execute the specified function.

    Creates a new thread with the specified name that will execute the specified function.

    This method may be safely called by any thread.

    name

      the name of the newly created thread

    fun

      the function to be executed by the newly created thread

    returns

      the newly created thread

26. #### def thread (fun: ⇒ Unit) : Thread

    Creates a new thread that will execute the specified function.

    Creates a new thread that will execute the specified function.

    The name of the thread will be of the form Conductor-Thread-N, where N is some integer.

    This method may be safely called by any thread.

    fun

      the function to be executed by the newly created thread

    returns

      the newly created thread

27. #### def toString () : String

    Returns a string representation of the object.

    Returns a string representation of the object.

    The default representation is platform dependent.

    returns

      a string representation of the object.

    definition classes: AnyRef → Any

28. #### def wait () : Unit

    attributes: final
    definition classes: AnyRef

29. #### def wait (arg0: Long, arg1: Int) : Unit

    attributes: final
    definition classes: AnyRef

30. #### def wait (arg0: Long) : Unit

    attributes: final
    definition classes: AnyRef

31. #### def waitForBeat (beat: Int) : Unit

    Blocks the current thread until the thread beat reaches the specified value, at which point the current thread will be unblocked.

    Blocks the current thread until the thread beat reaches the specified value, at which point the current thread will be unblocked.

    beat

      the tick value to wait for

32. #### def whenFinished (fun: ⇒ Unit) : Unit

    Invokes `conduct` and after `conduct` method returns, if `conduct` returns normally (i.

    Invokes `conduct` and after `conduct` method returns, if `conduct` returns normally (i.e., without throwing an exception), invokes the passed function.

    If `conduct` completes abruptly with an exception, this method will complete abruptly with the same exception and not execute the passed function.

    This method must be called by the thread that instantiated this `Conductor`, and that same thread will invoke `conduct` and, if it returns noramlly, execute the passed function.

    Because `whenFinished` invokes `conduct`, it can only be invoked once on a `Conductor` instance. As a result, if you need to pass a block of code to `whenFinished` it should be the last statement of your test. If you don't have a block of code that needs to be run once all the threads have finished successfully, then you can simply invoke `conduct` and never invoke`whenFinished`.

    fun

      the function to execute after `conduct` call returns

33. #### def withConductorFrozen [T] (fun: ⇒ T) : Unit

    Executes the passed function with the `Conductor` frozen so that it won't advance the clock.

    Executes the passed function with the `Conductor` frozen so that it won't advance the clock.

    While the `Conductor` is frozen, the beat will not advance. Once the passed function has completed executing, the `Conductor` will be unfrozen so that the beat will advance when all threads are blocked, as normal.

    fun

      the function to execute while the `Conductor` is frozen.

### Inherited from AnyRef

### Inherited from Any