1 /* 2 * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 5 package kotlinx.coroutines 6 7 import kotlinx.coroutines.internal.* 8 import kotlin.coroutines.* 9 10 /** 11 * Base class to be extended by all coroutine dispatcher implementations. 12 * 13 * The following standard implementations are provided by `kotlinx.coroutines` as properties on 14 * the [Dispatchers] object: 15 * 16 * * [Dispatchers.Default] — is used by all standard builders if no dispatcher or any other [ContinuationInterceptor] 17 * is specified in their context. It uses a common pool of shared background threads. 18 * This is an appropriate choice for compute-intensive coroutines that consume CPU resources. 19 * * [Dispatchers.IO] — uses a shared pool of on-demand created threads and is designed for offloading of IO-intensive _blocking_ 20 * operations (like file I/O and blocking socket I/O). 21 * * [Dispatchers.Unconfined] — starts coroutine execution in the current call-frame until the first suspension, 22 * whereupon the coroutine builder function returns. 23 * The coroutine will later resume in whatever thread used by the 24 * corresponding suspending function, without confining it to any specific thread or pool. 25 * **The `Unconfined` dispatcher should not normally be used in code**. 26 * * Private thread pools can be created with [newSingleThreadContext] and [newFixedThreadPoolContext]. 27 * * An arbitrary [Executor][java.util.concurrent.Executor] can be converted to a dispatcher with the [asCoroutineDispatcher] extension function. 28 * 29 * This class ensures that debugging facilities in [newCoroutineContext] function work properly. 30 */ 31 public abstract class CoroutineDispatcher : 32 AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor { 33 34 /** @suppress */ 35 @ExperimentalStdlibApi 36 public companion object Key : AbstractCoroutineContextKey<ContinuationInterceptor, CoroutineDispatcher>( 37 ContinuationInterceptor, <lambda>null38 { it as? CoroutineDispatcher }) 39 40 /** 41 * Returns `true` if the execution of the coroutine should be performed with [dispatch] method. 42 * The default behavior for most dispatchers is to return `true`. 43 * 44 * If this method returns `false`, the coroutine is resumed immediately in the current thread, 45 * potentially forming an event-loop to prevent stack overflows. 46 * The event loop is an advanced topic and its implications can be found in [Dispatchers.Unconfined] documentation. 47 * 48 * A dispatcher can override this method to provide a performance optimization and avoid paying a cost of an unnecessary dispatch. 49 * E.g. [MainCoroutineDispatcher.immediate] checks whether we are already in the required UI thread in this method and avoids 50 * an additional dispatch when it is not required. 51 * 52 * While this approach can be more efficient, it is not chosen by default to provide a consistent dispatching behaviour 53 * so that users won't observe unexpected and non-consistent order of events by default. 54 * 55 * Coroutine builders like [launch][CoroutineScope.launch] and [async][CoroutineScope.async] accept an optional [CoroutineStart] 56 * parameter that allows one to optionally choose the [undispatched][CoroutineStart.UNDISPATCHED] behavior to start coroutine immediately, 57 * but to be resumed only in the provided dispatcher. 58 * 59 * This method should generally be exception-safe. An exception thrown from this method 60 * may leave the coroutines that use this dispatcher in the inconsistent and hard to debug state. 61 */ isDispatchNeedednull62 public open fun isDispatchNeeded(context: CoroutineContext): Boolean = true 63 64 /** 65 * Dispatches execution of a runnable [block] onto another thread in the given [context]. 66 * This method should guarantee that the given [block] will be eventually invoked, 67 * otherwise the system may reach a deadlock state and never leave it. 68 * Cancellation mechanism is transparent for [CoroutineDispatcher] and is managed by [block] internals. 69 * 70 * This method should generally be exception-safe. An exception thrown from this method 71 * may leave the coroutines that use this dispatcher in the inconsistent and hard to debug state. 72 * 73 * This method must not immediately call [block]. Doing so would result in [StackOverflowError] 74 * when [yield] is repeatedly called from a loop. However, an implementation that returns `false` from 75 * [isDispatchNeeded] can delegate this function to `dispatch` method of [Dispatchers.Unconfined], which is 76 * integrated with [yield] to avoid this problem. 77 */ 78 public abstract fun dispatch(context: CoroutineContext, block: Runnable) 79 80 /** 81 * Dispatches execution of a runnable `block` onto another thread in the given `context` 82 * with a hint for the dispatcher that the current dispatch is triggered by a [yield] call, so that the execution of this 83 * continuation may be delayed in favor of already dispatched coroutines. 84 * 85 * Though the `yield` marker may be passed as a part of [context], this 86 * is a separate method for performance reasons. 87 * 88 * @suppress **This an internal API and should not be used from general code.** 89 */ 90 @InternalCoroutinesApi 91 public open fun dispatchYield(context: CoroutineContext, block: Runnable): Unit = dispatch(context, block) 92 93 /** 94 * Returns a continuation that wraps the provided [continuation], thus intercepting all resumptions. 95 * 96 * This method should generally be exception-safe. An exception thrown from this method 97 * may leave the coroutines that use this dispatcher in the inconsistent and hard to debug state. 98 */ 99 public final override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> = 100 DispatchedContinuation(this, continuation) 101 102 @InternalCoroutinesApi 103 public override fun releaseInterceptedContinuation(continuation: Continuation<*>) { 104 (continuation as DispatchedContinuation<*>).reusableCancellableContinuation?.detachChild() 105 } 106 107 /** 108 * @suppress **Error**: Operator '+' on two CoroutineDispatcher objects is meaningless. 109 * CoroutineDispatcher is a coroutine context element and `+` is a set-sum operator for coroutine contexts. 110 * The dispatcher to the right of `+` just replaces the dispatcher to the left. 111 */ 112 @Suppress("DeprecatedCallableAddReplaceWith") 113 @Deprecated( 114 message = "Operator '+' on two CoroutineDispatcher objects is meaningless. " + 115 "CoroutineDispatcher is a coroutine context element and `+` is a set-sum operator for coroutine contexts. " + 116 "The dispatcher to the right of `+` just replaces the dispatcher to the left.", 117 level = DeprecationLevel.ERROR 118 ) plusnull119 public operator fun plus(other: CoroutineDispatcher): CoroutineDispatcher = other 120 121 /** @suppress for nicer debugging */ 122 override fun toString(): String = "$classSimpleName@$hexAddress" 123 } 124 125