- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
why has the blocked thread detection been removed from actors scheduler?
Mon, 2010-03-01, 04:01
Back in 2.7.7 the FJTaskScheduler2 included code to detect when all threads are blocked and spawn new ones:
http://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_7_7_final/src/actors/scala/actors/FJTaskScheduler2.scala
The logic is no longer in it's replacement.http://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/actors/scala/actors/scheduler/ForkJoinScheduler.scala
I did some poking around in the ForkJoinPool classes and couldn't find anything similar, but that doesn't mean it's not there. ;-)
So, if it's moved, where is it? And if it's gone, why? It seems that without it receive-based actors could quickly consume the entire pool, leading to deadlock and/or starvation.
The logic is no longer in it's replacement.http://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/actors/scala/actors/scheduler/ForkJoinScheduler.scala
I did some poking around in the ForkJoinPool classes and couldn't find anything similar, but that doesn't mean it's not there. ;-)
So, if it's moved, where is it? And if it's gone, why? It seems that without it receive-based actors could quickly consume the entire pool, leading to deadlock and/or starvation.
Hi Erik,
Erik Engbrecht wrote:
> Back in 2.7.7 the FJTaskScheduler2 included code to detect when all
> threads are blocked and spawn new ones:
> http://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_7_7_final/src/a...
>
> The logic is no longer in it's replacement.
> http://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/actors/scala/a...
>
> I did some poking around in the ForkJoinPool classes and couldn't find
> anything similar, but that doesn't mean it's not there. ;-)
>
> So, if it's moved, where is it? And if it's gone, why? It seems that
> without it receive-based actors could quickly consume the entire pool,
> leading to deadlock and/or starvation.
The new resizing logic in `ForkJoinScheduler` builds on the interface
for "managed blocking" of `ForkJoinPool`. Managed blocking works as
follows. The scheduler contains the following method:
override def managedBlock(blocker: scala.concurrent.ManagedBlocker) {
ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker {
def block = blocker.block()
def isReleasable() = blocker.isReleasable
}, true)
}
This method is called whenever an actor invokes a blocking
`receive`-like operation. The `ManagedBlocker` for `receive` is
implemented as follows:
private object blocker extends scala.concurrent.ManagedBlocker {
def block() = {
Actor.this.suspendActor() // blocks underlying thread
true
}
def isReleasable =
!Actor.this.isSuspended
}
Basically, a `ManagedBlocker` allows the thread pool to decide when it
is safe to invoke the blocking operation, perhaps after increasing the
pool size. Furthermore, using the `isReleasable` method the pool can
test whether it's no longer necessary to block, in which case the pool
size can be re-adjusted to the state before the `ManagedBlocker` was
submitted.
The second Boolean parameter of the `ForkJoinPool.managedBlock` method
indicates whether the current level of parallelism should be maintained
or whether we only want to prevent starvation. In the former case
(true), a spare thread is activated if necessary to ensure a parallelism
level of "core pool size".
So, in the case of `receive`, `receiveWithin` etc. this logic prevents
deadlock and maintains a given number of non-blocked threads (defaulting
to core pool size). However, it will not spawn more than core pool size
threads if it's not absolutely necessary to achieve this. On the other
hand, managed blocking allows shrinking the pool size when additional
threads are no longer necessary.
Also, `managedBlock` is only called in blocking library methods (and
this is where the behavior differs from the 2.7.7 scheduler); other
blocking operations are not protected using `ManagedBlocker`s. I am
thinking about exposing `managedBlock` in some way to the user, so that
upon calling some blocking operation, she can tell the library "please
wrap this in a managed blocker and submit it to the pool".
Cheers,
Philipp