How to make atomic exchange -- Scala way?
Scala approach is to favor immutability whenever it is possible (and it's very often possible). Then you do not need anymore copy constructors, locks, mutex, etc.
For example, you can convert the iterator to a List
at object construction. Since lists are immutable, you can safely share them without having to lock:
class IteratorWrapper[A]( iter: Iterator[A] ) { val list = iter.toList def iteratorCopy = list.iterator}
Here, the IteratorWrapper
is also immutable. You can safely pass it around. But if you really need to change the wrapped iterator, you will need more demanding approaches. For instance you could:
- Use locks
- Transform the wrapper into an
Actor
- Use STM (akka or other implementations).
Clarifications: I lack information on your problem constraints. But here is how I understand it.
Several threads must traverse simultaneously an Iterator
. A possible approach is to copy it before passing the reference to the threads. However, Scala practice aims at sharing immutable objects that do not need to be copied.
With the copy strategy, you would write something like:
//A single iterator producerclass Producer { val iterator: Iterator[Foo] = produceIterator(...)}//Several consumers, living on different threadsclass Consumer( p: Producer ) { def consumeIterator = { val iteratorCopy = copy( p.iterator ) //BROKEN !!! while( iteratorCopy.hasNext ) { doSomething( iteratorCopy.next ) } } }
However, it is difficult (or slow) to implement a copy method which is thread-safe. A possible solution using immutability will be:
class Producer { val lst: List[Foo] = produceIterator(...).toList def iteratorCopy = list.iterator}class Consumer( p: Producer ) { def consumeIterator = { val iteratorCopy = p.iteratorCopy while( iteratorCopy.hasNext ) { doSomething( iteratorCopy.next ) } } }
The producer will call produceIterator
once at construction. It it immutable because its state is only a list which is also immutable. The iteratorCopy
is also thread-safe, because the list is not modified when creating the copy (so several thread can traverse it simultaneously without having to lock).
Note that calling list.iterator
does not traverse the list. So it will not decrease performances in any way (as opposed to really copying the iterator each time).