{"id":444789,"date":"2025-01-12T15:00:11","date_gmt":"2025-01-12T15:00:11","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=444789"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=444789","title":{"rendered":"<span>Kotlin Coroutines \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c: \u043e\u0442\u043c\u0435\u043d\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/6d9\/80d\/b28\/6d980db28edff29c39fad238be0c00db.jpeg\" width=\"1344\" height=\"768\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6d9\/80d\/b28\/6d980db28edff29c39fad238be0c00db.jpeg\" data-blurred=\"true\"\/><\/figure>\n<p><a href=\"https:\/\/habr.com\/en\/articles\/827866\/\" rel=\"noopener noreferrer nofollow\">\u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435<\/a> \u044f \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c, \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0437\u0430\u043a\u0430\u043f\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0442\u0430\u043a\u0443\u044e \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c \u043a\u0430\u043a Job \u0438 \u043a\u0430\u043a \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u043e\u0442\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b, \u0432 \u043e\u0431\u0449\u0435\u043c \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u043f\u043e\u0433\u043d\u0430\u043b\u0438!<\/p>\n<h2>\u0417\u043d\u0430\u043a\u043e\u043c\u0438\u043c\u0441\u044f \u0441 Job \u0438 JobSupport <\/h2>\n<p>\u0427\u0435\u0440\u043a\u0430\u043d\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code class=\"kotlin\">\/\/ parent coroutine launch {      \/\/ child coroutine 1     launch {          ...     }     \/\/ child coroutine 2     launch {          ...     } }.cancel()<\/code><\/pre>\n<p>\u041f\u043e \u043b\u043e\u0433\u0438\u043a\u0435 <a href=\"https:\/\/kotlinlang.org\/docs\/coroutines-basics.html#structured-concurrency\" rel=\"noopener noreferrer nofollow\">Structured Concurrency<\/a> \u043e\u0442\u043c\u0435\u043d\u0430 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u0434\u043e\u043b\u0436\u043d\u0430 \u043f\u0440\u0438\u0432\u0435\u0437\u0442\u0438 \u043a \u043e\u0442\u043c\u0435\u043d\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u043a\u043e\u0440\u0443\u0442\u0438\u043d (1 \u0438 2), \u044d\u0442\u043e \u043e\u0434\u043d\u043e \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u043f\u0440\u0430\u0432\u0438\u043b \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430.<\/p>\n<p>\u041f\u0440\u043e\u0432\u0430\u043b\u0438\u043c\u0441\u044f \u0432 \u043c\u0435\u0442\u043e\u0434 <code>cancel()<\/code> \u0438 \u0443\u0437\u043d\u0430\u0435\u043c \u043a\u043e\u043c\u0443 \u043e\u043d \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0438\u0442: <\/p>\n<pre><code class=\"kotlin\">interface Job : CoroutineContext.Element {     \/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u043e\u0447\u0435\u0440\u043d\u044e\u044e Job      fun attachChild(child: ChildJob): ChildHandle        \/\/ \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u0442 Job     fun cancel(cause: CancellationException? = null) }<\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434 <code>cancel()<\/code> \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0438\u0442 \u0442\u0430\u043a\u043e\u0439 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043a\u0430\u043a <code>Job<\/code>, \u044d\u0442\u043e \u043e\u0434\u0438\u043d \u0438\u0437 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 <code>CoroutineContext'\u0430<\/code>, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0439 \u0437\u0430 \u043e\u0434\u043d\u043e \u0438\u0437 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b: <\/p>\n<ol>\n<li>\n<p>\u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f<\/p>\n<\/li>\n<li>\n<p>\u043e\u0442\u043c\u0435\u043d\u0435\u043d\u0430<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439<\/p>\n<\/li>\n<li>\n<p>\u0435\u0449\u0435 \u043d\u0435 \u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f (\u0435\u0441\u043b\u0438 \u044d\u0442\u043e <a href=\"https:\/\/kotlinlang.org\/api\/kotlinx.coroutines\/kotlinx-coroutines-core\/kotlinx.coroutines\/-coroutine-start\/-l-a-z-y\/\" rel=\"noopener noreferrer nofollow\">lazy \u0437\u0430\u043f\u0443\u0441\u043a \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b<\/a>)<\/p>\n<\/li>\n<\/ol>\n<p>\u0412 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435 <code>Job<\/code> \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0437\u0432\u0430\u0442\u044c <a href=\"https:\/\/en.wikipedia.org\/wiki\/Finite-state_machine\" rel=\"noopener noreferrer nofollow\">\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u043c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u043e\u043c<\/a> &#8212; \u0435\u0441\u0442\u044c \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 &#171;\u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f&#187; \u0438 \u0435\u0441\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b \u0432 \u0434\u0440\u0443\u0433\u0438\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u0440\u0438 \u0432\u044b\u0431\u0440\u043e\u0441\u0435 <code>CancellationException<\/code> \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u0442 \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 &#171;\u043e\u0442\u043c\u0435\u043d\u0435\u043d\u0430&#187; \u0438 \u0442\u0434.<\/p>\n<p>\u0421 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f\u043c\u0438 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c, \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 <code>Job<\/code>, \u043e\u043d\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0432 <code>JobSupport<\/code>, \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c, \u0442\u0430\u043a\u0436\u0435 \u044d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0441\u0430\u043c\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430:<\/p>\n<pre><code class=\"kotlin\">abstract class AbstractCoroutine&lt;in T&gt;(     parentContext: CoroutineContext,     initParentJob: Boolean,     active: Boolean ) : JobSupport(active), Job, Continuation&lt;T&gt;, CoroutineScope { ... }<\/code><\/pre>\n<p>\u041a\u043b\u0430\u0441\u0441 <code>JobSupport<\/code> \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u043e\u0439, \u0431\u043e\u043b\u0435\u0435 1000 \u0441\u0442\u0440\u043e\u043a \u043a\u043e\u0434\u0430, \u043d\u043e \u043d\u0430\u0441 \u043f\u043e\u043a\u0430 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u0430 <code>cancel()<\/code>:<\/p>\n<pre><code class=\"kotlin\">\/\/ \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0432 JobSupport override fun cancel(cause: CancellationException?) {     cancelInternal(cause ?: defaultCancellationException()) }  \/\/ \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 cancelInternal() \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \/\/ \u043b\u043e\u0433\u0438\u043a\u0438 \u043e\u0442\u043c\u0435\u043d\u044b \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430\u0445, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0432 ChannelCoroutine open fun cancelInternal(cause: Throwable) {     cancelImpl(cause) }  \/\/ \u0434\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d \u0431\u0430\u0437\u043e\u0432\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u043e\u0442\u043c\u0435\u043d\u044b \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0442\u0443\u0442 internal fun cancelImpl(cause: Any?): Boolean {     var finalState: Any? = COMPLETING_ALREADY     if (onCancelComplete) {         \/\/ \u0442\u0443\u0442 \u043b\u043e\u0433\u0438\u043a\u0430 \u0442\u043e\u043a\u043e \u0434\u043b\u044f CompletableDeferred \u043a\u043e\u0440\u0443\u0442\u0438\u043d,          \/\/ \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0432 \u043d\u0438\u0445 \u0443\u0433\u043b\u0443\u0431\u043b\u044f\u0442\u044c\u0441\u044f     }          if (finalState === COMPLETING_ALREADY) {         \/\/ \u043d\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 \u044d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434         finalState = makeCancelling(cause)     }     \/\/ \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c true, \u0435\u0441\u043b\u0438 \u043e\u0442\u043c\u0435\u043d\u0430 \u0443\u0434\u0430\u043b\u0430\u0441\u044c      \/\/ \u0438\u043b\u0438 false \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043a\u0430\u043a\u0430\u044f-\u0442\u043e \u0444\u0438\u0433\u043d\u044f     return when {         finalState === COMPLETING_ALREADY -&gt; true         finalState === COMPLETING_WAITING_CHILDREN -&gt; true         finalState === TOO_LATE_TO_CANCEL -&gt; false         else -&gt; {             afterCompletion(finalState)             true         }     } }  \/\/ \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0442\u043c\u0435\u043d\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b private fun makeCancelling(cause: Any?): Any? {     var causeExceptionCache: Throwable? = null \/\/ lazily init result of createCauseException(cause)     loopOnState { state -&gt;         when (state) {             ...             \/\/ Incomplete \u044d\u0442\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b             is Incomplete -&gt; {                 val causeException = causeExceptionCache ?: createCauseException(cause).also { causeExceptionCache = it }                 if (state.isActive) {                     \/\/ \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0442\u043c\u0435\u043d\u044b \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b, \u043d\u0430\u0448 \u0441\u043b\u0443\u0447\u0430\u0439                     if (tryMakeCancelling(state, causeException)) return COMPLETING_ALREADY                 } else {                     \/\/ \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b (\u043d\u0435 \u043e\u0442\u043c\u0435\u043d\u0430)                     val finalState = tryMakeCompleting(state, CompletedExceptionally(causeException))                     when {                         finalState === COMPLETING_ALREADY -&gt; error(\"Cannot happen in $state\")                         finalState === COMPLETING_RETRY -&gt; return@loopOnState                         else -&gt; return finalState                     }                 }             }             else -&gt; return TOO_LATE_TO_CANCEL \/\/ already complete         }     } }<\/code><\/pre>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0438\u0434\u0442\u0438 \u0434\u0430\u043b\u044c\u0448\u0435 \u0445\u043e\u0442\u0435\u043b \u0431\u044b \u0443\u0442\u043e\u0447\u043d\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442:<\/p>\n<ol>\n<li>\n<p><code>COMPLETING_ALREADY<\/code> &#8212; \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0443\u0436\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430.<\/p>\n<\/li>\n<li>\n<p><code>COMPLETING_WAITING_CHILDREN<\/code> &#8212; \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043e\u0436\u0438\u0434\u0430\u0435\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0434\u0435\u0442\u0435\u0439.<\/p>\n<\/li>\n<li>\n<p><code>COMPLETING_RETRY<\/code> &#8212; \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043d\u0435 \u0441\u043c\u043e\u0433\u043b\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0441\u044f \u0438 \u043d\u0430\u0434\u043e \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0435\u0449\u0435 \u0440\u0430\u0437.<\/p>\n<\/li>\n<li>\n<p><code>TOO_LATE_TO_CANCEL<\/code> &#8212; \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043f\u043e\u0437\u0434\u043d\u043e \u0434\u043b\u044f \u043e\u0442\u043c\u0435\u043d\u044b \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b.<\/p>\n<\/li>\n<\/ol>\n<p>\u042d\u0442\u043e \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u0435\u0442\u043e\u0434 <code>cancelImpl<\/code> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u044e\u0449\u0435\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 (\u0435\u0441\u043b\u0438 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b\u0430\u0441\u044c):<\/p>\n<pre><code class=\"kotlin\">internal fun cancelImpl(cause: Any?): Boolean {     val finalState = ...        return when {         finalState === COMPLETING_ALREADY -&gt; true         finalState === COMPLETING_WAITING_CHILDREN -&gt; true         finalState === TOO_LATE_TO_CANCEL -&gt; false         else -&gt; {             afterCompletion(finalState)             true         }     } }<\/code><\/pre>\n<p><strong>\u0412\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442<\/strong>: \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043d\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 <code>Job'\u0435<\/code>, \u0430 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u0430 \u043b\u0435\u0442\u0443 \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a <code>cancel()<\/code> \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440.<\/p>\n<p>\u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u0430\u043a\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 <code>Job'\u0435<\/code> \u0438 \u043a\u0430\u043a \u043e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u044b.<\/p>\n<h2>\u0423\u0433\u043b\u0443\u0431\u043b\u044f\u0435\u043c\u0441\u044f \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f JobSupport<\/h2>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0437\u0430\u0447\u0435\u043c \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0443\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0434\u043b\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b:<\/p>\n<pre><code class=\"kotlin\">class Thread1 : Thread() {      private var isRunning = false      val isActive: Boolean         get() = isRunning          override fun run() {         isRunning = true         while (true) {             \/\/ \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0446\u0438\u043a\u043b \u043f\u043e\u043a\u0430 isRunning \u0440\u0430\u0432\u0435\u043d true             if (!isRunning) break             ...         }     }          fun cancel() {           \/\/ \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u043c \u0446\u0438\u043a\u043b         isRunning = false     }    }<\/code><\/pre>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043f\u043e\u0442\u043e\u043a <code>Thread1<\/code> \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043c\u0435\u043d\u0435\u043d, \u043b\u043e\u0433\u0438\u043a\u0430 \u0432\u043d\u0443\u0442\u0440\u0438 \u043d\u0435\u0433\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0441\u044f, \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u0442\u0430\u043d\u0435\u0442 \u043d\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u043c, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e:<\/p>\n<ol>\n<li>\n<p>\u0423\u0437\u043d\u0430\u0442\u044c \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b\u0441\u044f \u043f\u043e\u0442\u043e\u043a \u0438\u043b\u0438 \u043d\u0435\u0442.<\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0434\u043b\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f (\u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u0446\u0438\u043a\u043b).<\/p>\n<\/li>\n<\/ol>\n<p>\u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0434\u043b\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d, \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u0437\u043d\u0430\u0442\u044c \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u043e\u0439 \u0432 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043a\u0430\u043a\u0443\u044e-\u0442\u043e \u043b\u043e\u0433\u0438\u043a\u0443 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f.<\/p>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0441\u0430\u043c\u044b\u0435 \u0447\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0432 <code>JobSupport<\/code>:<\/p>\n<pre><code class=\"kotlin\">\/\/ \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u0430 \u043b\u0435\u0442\u0443 (\u043d\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 JobSupport) val COMPLETING_ALREADY = Symbol(\"COMPLETING_ALREADY\") val COMPLETING_WAITING_CHILDREN = Symbol(\"COMPLETING_WAITING_CHILDREN\") val COMPLETING_RETRY = Symbol(\"COMPLETING_RETRY\") val TOO_LATE_TO_CANCEL = Symbol(\"TOO_LATE_TO_CANCEL\")  \/\/ \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0435\u0439 \u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 EMPTY_ACTIVE val EMPTY_NEW = Empty(false) \/\/ \u0434\u043b\u044f lazy \u043a\u043e\u0440\u0443\u0442\u0438\u043d val EMPTY_ACTIVE = Empty(true) \/\/ \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u043a\u043e\u0440\u0443\u0442\u0438\u043d  \/\/ \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0432 \u0441\u0442\u0430\u0442\u0443\u0441\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0435\u0442 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u043a\u043e\u0440\u0443\u0442\u0438\u043d class Empty(override val isActive: Boolean) : Incomplete { ... }  \/\/ \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0442\u043e\u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u0447\u0442\u043e \u0438 Empty, \u0442\u043e\u043a\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \/\/ \u0441\u043f\u0438\u0441\u043e\u043a CompletionHandler'\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0437\u0432\u0430\u043d\u044b \u043f\u0440\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b class InactiveNodeList(     override val list: NodeList ) : Incomplete { ... }  \/\/ \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0432 \u0441\u0442\u0430\u0442\u0443\u0441\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0435\u0441\u0442\u044c \u043e\u0434\u043d\u0430 \u0434\u043e\u0447\u0435\u0440\u043d\u044f\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 class ChildHandleNode(     val childJob: ChildJob ) : JobNode(), ChildHandle { ... }  \/\/ \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0432 \u0441\u0442\u0430\u0442\u0443\u0441\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0435\u0441\u0442\u044c \u0431\u043e\u043b\u0435\u0435  \/\/ \u0447\u0435\u043c \u043e\u0434\u043d\u0430 \u0434\u043e\u0447\u0435\u0440\u043d\u044f\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 class NodeList : LockFreeLinkedListHead(), Incomplete { ... }  \/\/ \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0432 \u0441\u0442\u0430\u0442\u0443\u0441\u0435 \u043e\u0442\u043c\u0435\u043d\u044b \u0438\u043b\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \/\/ \u044d\u0442\u043e \u043d\u0435 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043e\u0431 \u044d\u0442\u043e\u043c \u0435\u0449\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0440\u0430\u0437\u0434\u0435\u043b class Finishing(     override val list: NodeList,     isCompleting: Boolean,     rootCause: Throwable? ) : SynchronizedObject(), Incomplete { ... }  \/\/ \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0431\u044b\u043b\u0430 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u043f\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u0432\u044b\u0431\u0440\u043e\u0441\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f:  \/\/ 1) CancellationException, \u0435\u0441\u043b\u0438 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0431\u044b\u043b\u0430 \u043e\u0442\u043c\u0435\u043d\u0435\u043d\u0430 \/\/ 2) \u043b\u044e\u0431\u044b\u0435 \u0434\u0440\u0443\u0433\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \/\/ \u044d\u0442\u043e \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043e\u0431 \u044d\u0442\u043e\u043c \u0435\u0449\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0440\u0430\u0437\u0434\u0435\u043b class CompletedExceptionally(val cause: Throwable) { ... }  \/\/ JobSupport \u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0432 atomic \u0442\u0438\u043f\u0435 \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u0438\u0442\u044c  \/\/ \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0443 \u043e\u0442 \u043e\u0448\u0438\u0431\u043e\u043a \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438 (race condition) val _state = atomic&lt;Any?&gt;(if (active) EMPTY_ACTIVE else EMPTY_NEW)<\/code><\/pre>\n<p>\u0412 <code>JobSupport'\u0435<\/code> \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0438\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0434\u043d\u043e \u0438\u0437 \u0432\u044b\u0448\u0435\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0445. <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0432 \u043f\u0440\u0438\u043a\u043b\u0430\u0434\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b, \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c\u0438 Boolean \u043f\u043e\u043b\u044f\u043c\u0438:<\/p>\n<pre><code class=\"kotlin\">\/\/ \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0432 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0435, \u0442\u0430\u043a \u043a\u0430\u043a \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442 JobSupport class JobSupport : Job {      \/\/ \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0438\u043b\u0438 \u043d\u0435\u0442     override val isActive: Boolean get() {         val state = this.state         return state is Incomplete &amp;&amp; state.isActive     }      \/\/ \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0438\u043b\u0438 \u043d\u0435\u0442 (\u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435)     override val isCompleted: Boolean get() {         return state !is Incomplete     }      \/\/ \u043e\u0442\u043c\u0435\u043d\u0435\u043d\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0438\u043b\u0438 \u043d\u0435\u0442     override val isCancelled: Boolean get() {         val state = this.state         return state is CompletedExceptionally || (state is Finishing &amp;&amp; state.isCancelling)     }    }<\/code><\/pre>\n<p>\u0414\u0443\u043c\u0430\u044e \u0432\u044b \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u043e\u0434\u043d\u043e \u0438\u0437 \u043d\u0438\u0445, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0432\u044b\u0437\u044b\u0432\u0430\u043b\u0438 <code>Job.ensureActive()<\/code> \u043c\u0435\u0442\u043e\u0434:<\/p>\n<pre><code class=\"kotlin\">fun Job.ensureActive(): Unit {     if (!isActive) throw getCancellationException() }<\/code><\/pre>\n<p>\u0421 <code>JobSupport<\/code> \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\u043c\u0438 \u0431\u043e\u043b\u0435\u0435 \u043c\u0435\u043d\u0435\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c, \u043c\u043e\u0436\u0435\u043c \u0441\u043d\u043e\u0432\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u043b\u043e\u0433\u0438\u043a\u0435:<\/p>\n<pre><code class=\"kotlin\">internal fun cancelImpl(cause: Any?): Boolean {     ...     val finalState = makeCancelling(cause)     ... }  private fun makeCancelling(cause: Any?): Any? {     when (state) {         ...         is Incomplete -&gt; tryMakeCancelling(state, causeException)     } }                <\/code><\/pre>\n<p>\u042f \u0443\u0436\u0435 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u043b \u043a\u043e\u0434 \u044d\u0442\u0438\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432, \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439 \u0440\u0430\u0437\u0434\u0435\u043b \u0435\u0441\u043b\u0438 \u0435\u0433\u043e \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u043b\u0438, \u0433\u043b\u0430\u0432\u043d\u043e\u0435 \u043f\u043e\u043d\u044f\u0442\u044c \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u0432\u044b\u0437\u043e\u0432\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u0438 \u043e\u0442\u043c\u0435\u043d\u0435:<\/p>\n<blockquote>\n<p>cancel() \u2192 cancelInternal() \u2192 cancelImpl() \u2192 makeCancelling() \u2192 tryMakeCancelling()<\/p>\n<\/blockquote>\n<p>\u041f\u043e \u0438\u0442\u043e\u0433\u0443 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 <code>JobSupport.tryMakeCancelling()<\/code>, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u043e\u0432\u0430\u043b\u0438\u043c\u0441\u044f \u0442\u0443\u0434\u0430:<\/p>\n<pre><code class=\"kotlin\">private fun tryMakeCancelling(state: Incomplete, rootCause: Throwable): Boolean {     assert { state !is Finishing } \/\/ only for non-finishing states     assert { state.isActive } \/\/ only for active states     \/\/ \u0431\u0435\u0440\u0435\u043c \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 Job'\u044b \u0438\u0437 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b     val list = getOrPromoteCancellingList(state) ?: return false     \/\/ \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 - \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043e\u0442\u043c\u0435\u043d\u044b \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b     val cancelling = Finishing(list, false, rootCause)     \/\/ \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u043f\u043e\u0442\u043e\u043a\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \"\u0421\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u0441 \u043e\u0431\u043c\u0435\u043d\u043e\u043c\"     \/\/ \u0443 \u043c\u0435\u043d\u044f \u0431\u044b\u043b \u043f\u043e\u0441\u0442 \u043d\u0430 \u044d\u0442\u043e\u0442 \u0441\u0447\u0435\u0442: https:\/\/t.me\/android_under_the_hood\/86      if (!_state.compareAndSet(state, cancelling)) return false     \/\/ \u043f\u0440\u043e\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u043c \u0434\u0430\u043b\u044c\u0448\u0435 \u043e\u0442\u043c\u0435\u043d\u0443     notifyCancelling(list, rootCause)     return true }<\/code><\/pre>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443, \u043f\u0440\u0438 \u043e\u0442\u043c\u0435\u043d\u0435 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0432\u0435\u0449\u0438:<\/p>\n<ol>\n<li>\n<p>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 <code>Job<\/code> (\u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0439\u0442\u0435 \u0447\u0442\u043e \u0441\u0430\u043c\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442 <code>JobSupport<\/code> \u0438 \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0442\u043e\u0436\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <code>Job'\u043e\u0439<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f <code>Finishing<\/code> \u0438 \u0435\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f \u0438 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 <code>Job<\/code> \u043e\u0431 \u043e\u0442\u043c\u0435\u043d\u0435.<\/p>\n<\/li>\n<\/ol>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c\u0441\u044f \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0441 1 \u0438 3 \u043f\u0443\u043d\u043a\u0442\u0430\u043c\u0438.<\/p>\n<h2>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 Job<\/h2>\n<p>\u0412\u0441\u043f\u043e\u043c\u043d\u0438\u043c \u0432\u043e\u0442 \u0442\u0430\u043a\u043e\u0439 \u043a\u043e\u0434 \u0432 <code>AbstractCoroutine<\/code>:<\/p>\n<pre><code class=\"kotlin\">\/\/ \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0439 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u043e\u043d\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e Job init {     if (initParentJob) initParentJob(parentContext[Job]) }  protected fun initParentJob(parent: Job?) {     assert { parentHandle == null }     if (parent == null) {         parentHandle = NonDisposableHandle         return     }     parent.start()      \/\/ parent.attachChild() \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 parent'\u0430      \/\/ \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0434\u043e\u0447\u0435\u0440\u043d\u044e\u044e Job'\u0443     val handle = parent.attachChild(this)     \/\/ parentHandle \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u043e\u0442\u043c\u0435\u043d\u044b \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b,     \/\/ \u0435\u0449\u0435 \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u044d\u0442\u043e\u043c\u0443     parentHandle = handle     \/\/ \u0435\u0441\u043b\u0438 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0431\u044b\u043b\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u0442\u043e \u0432\u0441\u0435 \u0437\u0430\u043d\u0443\u043b\u044f\u0435\u043c     if (isCompleted) {         handle.dispose()         parentHandle = NonDisposableHandle \/\/ release it just in case, to aid GC     } }<\/code><\/pre>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0432\u0435\u0449\u0438:<\/p>\n<ol>\n<li>\n<p>\u0418\u0437 <code>CoroutineContext'\u0430<\/code> \u0431\u0435\u0440\u0435\u0442\u0441\u044f \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f <code>Job'\u0430<\/code> \u0438 \u0435\u0441\u043b\u0438 \u043e\u043d\u0430 \u0435\u0441\u0442\u044c \u0442\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0443 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0435\u0439 <code>Job'\u044b<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f <code>ChildHandle<\/code>, \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u043c\u0435\u043d\u0438\u0442 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e <code>Job'\u0443<\/code> \u0435\u0441\u043b\u0438 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0431\u0440\u043e\u0448\u0435\u043d\u0430 \u043e\u0448\u0438\u0431\u043a\u0430.<\/p>\n<\/li>\n<\/ol>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u0435\u0436\u0434\u0443 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430\u043c\u0438 \u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u0432\u044f\u0437\u044c &#171;\u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c &#8212; \u0440\u0435\u0431\u0435\u043d\u043e\u043a&#187;, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0442\u0435\u043f\u0435\u0440\u044c \u0443\u0437\u043d\u0430\u0435\u043c \u043a\u0430\u043a \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 <code>Job'\u044b<\/code> \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0438 \u043a\u0430\u043a \u043e\u043d\u0438 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u044e\u0442\u0441\u044f \u043e\u0442\u0442\u0443\u0434\u0430:<\/p>\n<pre><code class=\"kotlin\">\/\/ \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 Job'\u044b \u0431\u0435\u0440\u0443\u0442\u0441\u044f \u0438\u0437 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b (JobSupport) fun getOrPromoteCancellingList(state: Incomplete): NodeList? = state.list ?:     when (state) {         is Empty -&gt; NodeList()         is JobNode -&gt; state.toSingleNodeList()         else -&gt; error(\"State should have list: $state\")     }  \/\/ \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0434\u043e\u0447\u0435\u0440\u043d\u0435\u0439 Job'\u044b \u0443 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 fun attachChild(child: ChildJob): ChildHandle {     val node = ChildHandleNode(child)     node.parentJob = this     val state = _state.value     when (state) {         is Empty -&gt; {              _state.value = node         }         is Incomplete -&gt; {             _state.value = when (val list = state.list) {                 null -&gt; node.toSingleNodeList()                 else -&gt; list + node.toSingleNodeList()             }         }     } }<\/code><\/pre>\n<p>\u042f \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u043b <code>JobSupport.attachChild()<\/code> \u0434\u043b\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u0441\u0443\u0442\u0438, \u0435\u0441\u043b\u0438 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e \u0443\u0437\u043d\u0430\u0442\u044c \u0432\u0441\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 \u043a\u0430\u0447\u0430\u0439\u0442\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438).<\/p>\n<p>\u041f\u043e \u0438\u0442\u043e\u0433\u0443 \u0432\u0441\u0435 \u0441\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043a \u0435\u0434\u0438\u043d\u043e\u043c\u0443 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e <code>JobSupport<\/code>, \u0433\u0434\u0435 \u0438 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 <code>Job'\u044b<\/code>, \u043a\u0430\u043a\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438 \u0432 \u043a\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u043f\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043b\u043e\u0433\u0438\u043a\u0435:<\/p>\n<ol>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0443 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u043d\u0435\u0442 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 <code>Job<\/code> \u0442\u043e \u043e\u043d\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 <code>Empty<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0443 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u0435\u0441\u0442\u044c \u043e\u0434\u043d\u0430 \u0434\u043e\u0447\u0435\u0440\u043d\u044f\u044f <code>Job<\/code> \u0442\u043e \u043e\u043d\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 <code>JobNode<\/code> (\u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 <code>ChildHandleNode<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0443 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 <code>Job<\/code> \u0442\u043e \u043e\u043d\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 <code>NodeList<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0445\u0440\u0430\u043d\u0438\u0442 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 <code>JobNode<\/code> \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0432 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u043c \u0441\u043f\u0438\u0441\u043a\u0435.<\/p>\n<\/li>\n<\/ol>\n<p>\u0427\u0442\u043e \u0436 \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0437\u043d\u0430\u0435\u043c \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u0432\u043b\u0435\u0447\u044c \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 <code>Job'\u044b<\/code> \u0438 \u0437\u043d\u0430\u0435\u043c \u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u043d\u0430 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f <code>parentHandle<\/code>, \u0442\u0435\u043f\u0435\u0440\u044c \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u0432\u0435\u0434\u043e\u043c\u0438\u0442\u044c \u0438\u0445 \u043e\u0431 \u043e\u0442\u043c\u0435\u043d\u0435.<\/p>\n<h2>\u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f \u0438 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 Job \u043e\u0431 \u043e\u0442\u043c\u0435\u043d\u0435<\/h2>\n<p>\u041f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c \u043a\u0430\u043a \u0437\u0430\u0440\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0432\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u044c \u0447\u0442\u043e \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c\u0441\u044f \u043f\u043e \u0434\u0432\u0443\u043c \u0440\u0430\u0437\u043d\u044b\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c:<\/p>\n<ol>\n<li>\n<p>\u041a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u0441\u044f \u0448\u0442\u0430\u0442\u043d\u043e, \u0447\u0435\u0440\u0435\u0437 \u0432\u044b\u0437\u043e\u0432 <code>Job.cancel()<\/code> \u043c\u0435\u0442\u043e\u0434\u0430, \u0432 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u043e\u0437\u0434\u0430\u0441\u0442\u0441\u044f \/ \u0432\u044b\u0431\u0440\u043e\u0441\u0438\u0442\u0441\u044f <code>CancellationException<\/code>, \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u0441\u044f \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0438 \u043e\u0442\u043c\u0435\u043d\u044f\u0442\u0441\u044f \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435, \u0432 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0431\u0440\u043e\u0448\u0435\u043d\u043e.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u0441\u044f \u0432\u043d\u0435\u0448\u0442\u0430\u0442\u043d\u043e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0432\u044b\u0432\u0430\u043b\u0438\u0442\u0441\u044f \u043b\u044e\u0431\u043e\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043e\u0442\u043b\u0438\u0447\u043d\u043e\u0435 \u043e\u0442 <code>CancellationException<\/code>, \u0432 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u0441\u044f \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430, \u043e\u0442\u043c\u0435\u043d\u044f\u0442\u0441\u044f \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u0438 \u0435\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d <code>SupervisorJob<\/code> \u0442\u043e \u043e\u0442\u043c\u0435\u043d\u0430 \u0442\u0430\u043a\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u043a\u0438\u043d\u0443\u0442\u0430 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044e.<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u0430\u043a \u044d\u0442\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u0432 \u043a\u043e\u0434\u0435:<\/p>\n<pre><code class=\"kotlin\">private fun tryMakeCancelling(state: Incomplete, rootCause: Throwable): Boolean {     ...     \/\/ \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u044f\u0435\u043c \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f \u0438 \u0434\u0435\u0442\u0435\u0439 \u043e\u0431 \u043e\u0442\u043c\u0435\u043d\u0435     \/\/ list \u044d\u0442\u043e \u0441\u043f\u0438\u0441\u043e\u043a Job, \u0432\u0437\u044f\u0442\u044b\u0439 \u0438\u0437 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b (JobSupport)     notifyCancelling(list, rootCause)     return true }  private fun notifyCancelling(list: NodeList, cause: Throwable) {     ...     \/\/ \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u043d\u0438\u0435 \u043e\u0442\u043c\u0435\u043d\u044b \u0432 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 Job'\u044b     notifyHandlers(list, cause) { it.onCancelling }     \/\/ \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u043d\u0438\u0435 \u043e\u0442\u043c\u0435\u043d\u044b \u0432 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e Job'\u0443     cancelParent(cause) }  \/\/ \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 Job \u043e\u0431 \u043e\u0442\u043c\u0435\u043d\u0435 private inline fun notifyHandlers(list: NodeList, cause: Throwable?, predicate: (JobNode) -&gt; Boolean) {     var exception: Throwable? = null     list.forEach { node -&gt;         \/\/ \u043f\u0440\u043e\u0431\u0435\u0433\u0430\u0435\u043c\u0441\u044f \u043f\u043e \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u043c Job'\u0430\u043c \u0438 \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u043c \u0438\u0445         \/\/ \u043a\u0430\u043a \u043c\u044b \u0443\u0436\u0435 \u0437\u043d\u0430\u0435\u043c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u043c JobNode \u0443\u0437\u043b\u043e\u043c \u0434\u043b\u044f          \/\/ \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u043a\u043e\u0440\u0443\u0442\u0438\u043d \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f ChildHandleNode         if (node is JobNode &amp;&amp; predicate(node)) {             try {                 node.invoke(cause)             } catch (ex: Throwable) {                 exception?.apply { addSuppressed(ex) } ?: run {                     exception = CompletionHandlerException(\"Exception in completion handler $node for $this\", ex)                 }             }         }     }     \/\/ \u0435\u0441\u043b\u0438 \u043f\u0440\u0438 \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u0438 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 JobNode \u0443\u0437\u043b\u043e\u0432 \u043e\u0431 \u043e\u0442\u043c\u0435\u043d\u0435 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e      \/\/ \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435, \u0442\u043e \u043e\u043d\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442\u0441\u044f \u0432 CoroutineExceptionHandler'\u0435,      \/\/ \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u0442 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443 \u0441\u043e stacktrace'\u043e\u043c     exception?.let { handleOnCompletionException(it) } }  \/\/ \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 Job'\u044b \u043e\u0431 \u043e\u0442\u043c\u0435\u043d\u0435 private fun cancelParent(cause: Throwable): Boolean {     \/\/ isScopedCoroutine \u0440\u0430\u0432\u0435\u043d true \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0445      \/\/ \u0447\u0435\u0440\u0435\u0437 coroutineScope { ... } \u0431\u0438\u043b\u0434\u0435\u0440, \u0442\u0430\u043a\u0438\u0435 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442      \/\/ \u043a\u0430\u043a suspend \u0431\u043b\u043e\u043a: \u043f\u0440\u043e\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u044e\u0442 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e      \/\/ throw exception, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a      \/\/ \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0435 \u0447\u0435\u0440\u0435\u0437 parentHandle     if (isScopedCoroutine) return true      \/\/ \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430: \u0448\u0442\u0430\u0442\u043d\u0430\u044f \u043e\u0442\u043c\u0435\u043d\u0430 \u0438\u043b\u0438 \u043d\u0435\u0442     val isCancellation = cause is CancellationException     val parent = parentHandle     \/\/ \u0435\u0441\u043b\u0438 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f \u043d\u0435\u0442, \u043d\u0438\u0447\u0435\u0433\u043e \u0441 \u043d\u0438\u043c \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435 \u043d\u0430\u0434\u043e     if (parent === null || parent === NonDisposableHandle) {         return isCancellation     }      \/\/ \u043e\u043f\u043e\u0432\u0435\u0449\u0430\u0435\u043c \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e Job'\u0443 \u043e\u0431 \u043e\u0442\u043c\u0435\u043d\u0435     return parent.childCancelled(cause) || isCancellation }<\/code><\/pre>\n<p>\u0412 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u043c \u0438\u0442\u043e\u0433\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0437\u0432\u0430\u043d\u044b:<\/p>\n<ol>\n<li>\n<p><code>ChildHandleNode.invoke()<\/code> \u0434\u043b\u044f \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u044f \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 <code>Job<\/code> \u043e\u0431 \u043e\u0442\u043c\u0435\u043d\u0435 &#8212; \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 <code>ChildHandleNode<\/code> \u0443\u0437\u043b\u044b \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 <code>JobSupport<\/code>.<\/p>\n<\/li>\n<li>\n<p><code>ChildHandleNode.childCancelled()<\/code> \u0434\u043b\u044f \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u044f \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 <code>Job'\u044b<\/code> \u043e\u0431 \u043e\u0442\u043c\u0435\u043d\u0435 &#8212; \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 <code>ChildHandleNode<\/code> \u0443\u0437\u0435\u043b \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0432 \u043f\u043e\u043b\u0435 <code>parentHandle<\/code>, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0438\u0442 \u043a\u043b\u0430\u0441\u0441\u0443 <code>JobSupport<\/code>.<\/p>\n<\/li>\n<\/ol>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u043e\u0431\u043b\u0438\u0436\u0435 \u043a\u043b\u0430\u0441\u0441 <code>ChildHandleNode<\/code>:<\/p>\n<pre><code class=\"kotlin\">class ChildHandleNode(     @JvmField val childJob: ChildJob ) : JobNode(), ChildHandle {     override val parent: Job get() = job     override val onCancelling: Boolean get() = true     \/\/ \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 invoke() \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u0447\u0435\u0440\u043d\u044f\u044f Job'\u0430     override fun invoke(cause: Throwable?) = childJob.parentCancelled(job)     \/\/ \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 childCancelled() \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f Job'\u0430     override fun childCancelled(cause: Throwable): Boolean = job.childCancelled(cause) }  open class JobSupport constructor(active: Boolean) : Job, ChildJob, ParentJob {      \/\/ \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u043e\u0447\u0435\u0440\u043d\u0435\u0439 Job'\u043e\u0439 \u0434\u043b\u044f \u043e\u0442\u043c\u0435\u043d\u044b \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439     open fun childCancelled(cause: Throwable): Boolean {         \/\/ \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f Job'\u0430 \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u043d\u0435\u0448\u0442\u0430\u0442\u043d\u043e\u0439 \u043e\u0442\u043c\u0435\u043d\u044b         if (cause is CancellationException) return true         return cancelImpl(cause) &amp;&amp; handlesException     }      \/\/ \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 Job'\u043e\u0439 \u0434\u043b\u044f \u043e\u0442\u043c\u0435\u043d\u044b \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445     override fun parentCancelled(parentJob: ParentJob) {         \/\/ \u0434\u043e\u0447\u0435\u0440\u043d\u044f\u044f Job'\u0430 \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0432\u0441\u0435\u0433\u0434\u0430 \u043a\u043e\u0433\u0434\u0430 \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f         cancelImpl(parentJob)     }  }  \/\/ \u043a\u043b\u0430\u0441\u0441 JobImpl \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442 JobSupport class SupervisorJobImpl(parent: Job?) : JobImpl(parent) {      \/\/ \u0432 SupervisorJob \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f Job'\u0430 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f     override fun childCancelled(cause: Throwable): Boolean = false    }<\/code><\/pre>\n<p>\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044f\u0441\u044c \u043a \u0434\u0432\u0443\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430\u043c \u043e\u0442\u043c\u0435\u043d\u044b \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b, \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0445 \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0430, \u043c\u043e\u0436\u0435\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0432\u044b\u0432\u043e\u0434\u044b: <\/p>\n<ol>\n<li>\n<p><strong>\u0428\u0442\u0430\u0442\u043d\u0430\u044f \u043e\u0442\u043c\u0435\u043d\u0430<\/strong>: \u043e\u0442\u043c\u0435\u043d\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u0442 \u043a \u0432\u044b\u0437\u043e\u0432\u0443 <code>JobSupport.cancelImpl()<\/code> \u0443 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 <code>Job<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u0442\u044c \u043e\u0442\u043c\u0435\u043d\u0443 \u0432\u0441\u0435 \u043d\u0438\u0436\u0435 \u0438 \u043d\u0438\u0436\u0435 \u043f\u043e \u0434\u0435\u0440\u0435\u0432\u0443 \u043f\u043e\u043a\u0430 \u043d\u0435 \u043e\u0442\u043c\u0435\u043d\u044f\u0442\u0441\u044f \u0432\u0441\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b, \u043f\u043e \u0438\u0442\u043e\u0433\u0443 \u043e\u0442\u043c\u0435\u043d\u0435\u043d\u043d\u044b\u0435 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u0431\u0443\u0434\u0443\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 <code>Finishing<\/code> &#8212; \u0442\u043e \u0435\u0441\u0442\u044c \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u043e\u0442\u043c\u0435\u043d\u044b.<\/p>\n<\/li>\n<li>\n<p><strong>\u0412\u043d\u0435\u0448\u0442\u0430\u0442\u043d\u0430\u044f \u043e\u0442\u043c\u0435\u043d\u0430<\/strong>: \u043e\u0442\u043c\u0435\u043d\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u0442 \u0432 \u0432\u044b\u0437\u043e\u0432\u0443 <code>JobSupport.cancelImpl()<\/code> \u0443 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 <code>Job<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0442\u043c\u0435\u043d\u044f\u0442\u0441\u044f \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0448\u0442\u0430\u0442\u043d\u043e\u0439 \u043e\u0442\u043c\u0435\u043d\u0435, \u0432 \u0434\u043e\u0431\u0430\u0432\u043e\u043a \u0435\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043b\u0438 <code>SupervisorJob<\/code> \u043e\u0442\u043c\u0435\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f\u043c \u0432\u0441\u0435 \u0432\u044b\u0448\u0435 \u0438 \u0432\u044b\u0448\u0435 \u043f\u043e \u0434\u0435\u0440\u0435\u0432\u0443 \u043f\u043e\u043a\u0430 \u043d\u0435 \u0434\u043e\u0439\u0434\u0435\u0442 \u0434\u043e \u0441\u0430\u043c\u043e\u0433\u043e \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e, \u0433\u0434\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u043a\u0438\u043d\u0443\u0442\u043e \u0432 <code>CoroutineExceptionHandler<\/code> (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d <code>CoroutineExceptionHandler<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u0440\u0430\u0448\u0438\u0442 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443 \u0441\u043e stacktrace&#8217;\u043e\u043c). <\/p>\n<\/li>\n<\/ol>\n<p>\u0412\u0440\u043e\u0434\u0435 \u0431\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c \u0441 \u043e\u0442\u043c\u0435\u043d\u043e\u0439, \u043d\u043e \u043a\u0430\u043a \u0431\u0443\u0434\u0442\u043e \u0447\u0435\u0433\u043e-\u0442\u043e \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u0434\u0430 \u043c\u044b \u0441\u0431\u0440\u043e\u0441\u0438\u043b\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u043d\u0430 <code>Finishing<\/code>, \u043d\u043e \u043d\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c \u043a\u0430\u043a \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043e\u0442\u043c\u0435\u043d\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043a\u0430\u043a \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>delay()<\/code> \u0438\u043b\u0438 \u043a\u0430\u043a \u043e\u0442\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f suspend \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0447\u0442\u043e \u0436 \u043f\u043e\u0440\u0430 \u0438 \u0432 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f.<\/p>\n<h2>\u041a\u0430\u043a \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f delay()<\/h2>\n<p>\u041e\u0441\u0432\u0435\u0436\u0443 \u043f\u0430\u043c\u044f\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0438\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c:<\/p>\n<pre><code class=\"kotlin\">val job = launch {     \/\/ \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 200 \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434     delay(1_000) } delay(200) \/\/ \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u043c \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0443 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 delay() \u0432\u044b\u0437\u043e\u0432\u043e\u043c job.cancel()<\/code><\/pre>\n<p>\u0412 \u043f\u0440\u043e\u0448\u043b\u044b\u0445 \u0440\u0430\u0437\u0434\u0435\u043b\u0430\u0445 \u043c\u044b \u0443\u0437\u043d\u0430\u043b\u0438 \u0447\u0442\u043e \u0432 \u0441\u0430\u043c\u043e\u0439 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0435 \u043d\u0435\u0442 \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043e\u0442\u043c\u0435\u043d\u044b \u043b\u043e\u0433\u0438\u043a\u0438, \u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u0438 \u043f\u0440\u043e\u0431\u0440\u043e\u0441 \u043e\u0442\u043c\u0435\u043d\u044b \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \/ \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u043c \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043b\u0435\u0437\u0435\u043c \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 <code>delay()<\/code> \u0444\u0443\u043d\u043a\u0446\u0438\u0438:<\/p>\n<pre><code class=\"kotlin\">suspend fun delay(timeMillis: Long) {     if (timeMillis &lt;= 0) return     \/\/ \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0443 \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440 \u043f\u043e\u043a\u0430      \/\/ \u043d\u0435 \u0432\u044b\u0437\u043e\u0432\u0435\u0442\u0441\u044f Continuation.resumeWith(), \u044d\u0442\u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442     \/\/ \u0441\u043f\u0443\u0441\u0442\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f timeMillis, \u0442\u0430\u043a \u0432 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435 \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 delay()     return suspendCancellableCoroutine sc@ { cont: CancellableContinuation&lt;Unit&gt; -&gt;         \/\/ if timeMillis == Long.MAX_VALUE then just wait forever like awaitCancellation, don't schedule.         if (timeMillis &lt; Long.MAX_VALUE) {             cont.context.delay.scheduleResumeAfterDelay(timeMillis, cont)         }     } }  \/\/ \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f delay() \u0438\u0437 Android \u0434\u0438\u0441\u043f\u0430\u0442\u0447\u0435\u0440\u0430 HandlerContext,  \/\/ \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation&lt;Unit&gt;) {     val block = Runnable {         with(continuation) { resumeUndispatched(Unit) }     }     \/\/ \u0441\u0442\u0430\u0432\u0438\u043c \u0437\u0430\u0434\u0430\u0447\u0443 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430, \u0432\u0442\u043e\u0440\u043e\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440     \/\/ \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434 \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430     if (handler.postDelayed(block, timeMillis.coerceAtMost(MAX_DELAY))) {         \/\/ CancellableContinuation \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a,         \/\/ \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d \u043f\u0440\u0438 \u043e\u0442\u043c\u0435\u043d\u0435 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b,          \/\/ \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438 \u0438\u0437 \u043e\u0447\u0435\u0440\u0435\u0434\u0438         continuation.invokeOnCancellation { handler.removeCallbacks(block) }     } }<\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u0437\u043d\u0430\u0442\u044c \u043a\u0442\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043e\u0442\u043c\u0435\u043d\u044b, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u0447\u0435\u0440\u0435\u0437 <code>CancellableContinuation.invokeOnCancellation()<\/code> \u043c\u0435\u0442\u043e\u0434. \u0427\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432 \u044d\u0442\u043e\u043c \u043f\u0440\u043e\u0432\u0430\u043b\u0438\u043c\u0441\u044f \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>suspendCancellableCoroutine<\/code>:<\/p>\n<pre><code class=\"kotlin\">suspend inline fun &lt;T&gt; suspendCancellableCoroutine(     crossinline block: (CancellableContinuation&lt;T&gt;) -&gt; Unit ): T =     suspendCoroutineUninterceptedOrReturn { uCont -&gt;         \/\/ \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u043c\u044b\u0439 Continuation \u0438 \u0432 \u043d\u0435\u0433\u043e \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u0435\u043a\u0443\u0449\u0438\u0439,         \/\/ \u0447\u0442\u043e\u0431\u044b \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043e\u0431\u0440\u0430\u0442\u043d\u043e         val cancellable = CancellableContinuationImpl(uCont.intercepted(), resumeMode = MODE_CANCELLABLE)         \/\/ \u0442\u0443\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 CancellableContinuationImpl \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435         \/\/ \u0434\u043e\u0447\u0435\u0440\u043d\u0435\u0433\u043e JobNode \u0443\u0437\u043b\u0430 \u0434\u043b\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b         cancellable.initCancellability()         block(cancellable)         \/\/ \u0435\u0441\u043b\u0438 \u043c\u043e\u0436\u0435\u043c \u0441\u0440\u0430\u0437\u0443 \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0435\u0433\u043e          \/\/ \u0438\u043b\u0438 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0443 \u0435\u0441\u043b\u0438 \u044d\u0442\u043e \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e         cancellable.getResult()     }  \/\/ \u043c\u0435\u0442\u043e\u0434 \u0438\u0437 CancellableContinuationImpl fun initCancellability() {     val handle = installParentHandle() ?: return      ... }  \/\/ \u043c\u0435\u0442\u043e\u0434 \u0438\u0437 CancellableContinuationImpl private fun installParentHandle(): DisposableHandle? {     \/\/ \u0431\u0435\u0440\u0435\u043c \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e Job'\u0443, \u0435\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430     val parent = context[Job] ?: return null     \/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 Job'\u044b \u043d\u043e\u0432\u044b\u0439 \u0443\u0437\u0435\u043b ChildContinuation     val handle = parent.invokeOnCompletion(handler = ChildContinuation(this))     _parentHandle.compareAndSet(null, handle)     return handle }  private class ChildContinuation(     @JvmField val child: CancellableContinuationImpl&lt;*&gt; ) : JobNode() {     override val onCancelling get() = true      \/\/ \u044d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d \u043a\u043e\u0433\u0434\u0430 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f Job'\u0430     \/\/ \u043d\u0430\u0447\u043d\u0435\u0442 \u043e\u0442\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f, \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u0442\u0435 \u043a\u0430\u043a \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u044f\u0435\u0442      \/\/ \u043e\u0431 \u043e\u0442\u043c\u0435\u043d\u0435 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u0435\u0439 \u0438 \u0434\u0435\u0442\u0435\u0439     override fun invoke(cause: Throwable?) {         \/\/ \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f CancellableContinuationImpl         child.parentCancelled(child.getContinuationCancellationCause(job))     } }<\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u044b \u0443\u0436\u0435 \u0437\u043d\u0430\u0435\u0442\u0435 \u043f\u0440\u0438 \u043e\u0442\u043c\u0435\u043d\u0435 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u0432\u043e\u0437\u044c\u043c\u0443\u0442\u0441\u044f \u0432\u0441\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 <code>JobNode<\/code> \u0443\u0437\u043b\u044b \u0438\u0437 \u0435\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u0443 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0443\u0437\u043b\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d \u043c\u0435\u0442\u043e\u0434 <code>JobNode.invoke()<\/code>, \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 <code>ChildContinuation<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u0442\u0430\u043a\u0438\u043c \u0436\u0435 \u0443\u0437\u043b\u043e\u043c, \u043a\u0430\u043a \u0438 <code>ChildHandleNode<\/code>:<\/p>\n<pre><code class=\"kotlin\">class ChildContinuation(val child: CancellableContinuationImpl&lt;*&gt;) : JobNode() {     override fun invoke(cause: Throwable?) {         \/\/ \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 JobNode.invoke() \u0443 CancellationContinuation \u0431\u0443\u0434\u0435\u0442         \/\/ \u0432\u044b\u0437\u0432\u0430\u043d \u043c\u0435\u0442\u043e\u0434 parentCancelled()         child.parentCancelled(child.getContinuationCancellationCause(job))     } }  \/\/ \u043c\u0435\u0442\u043e\u0434 \u0438\u0437 CancellableContinuationImpl internal fun parentCancelled(cause: Throwable) {     if (cancelLater(cause)) return     \/\/ \u043f\u043e \u0438\u0442\u043e\u0433\u0443 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442 \u043e\u0431\u044b\u0447\u043d\u0430\u044f \u043e\u0442\u043c\u0435\u043d\u0430 \u0447\u0435\u0440\u0435\u0437      \/\/ CancellableContinuationImpl.cancel() \u043c\u0435\u0442\u043e\u0434     cancel(cause)     \/\/ Even if cancellation has failed, we should detach child to avoid potential leak     detachChildIfNonResuable() }<\/code><\/pre>\n<p>\u041d\u0443 \u0438 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043a\u0430\u043a \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0442\u043c\u0435\u043d\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0432 <code>CancellableContinuationImpl<\/code>:<\/p>\n<pre><code class=\"kotlin\">\/\/ \u043c\u0435\u0442\u043e\u0434 \u0438\u0437 CancellableContinuationImpl override fun cancel(cause: Throwable?): Boolean {     _state.loop { state -&gt;         if (state !is NotCompleted) return false \/\/ false if already complete or cancelling         \/\/ \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043d\u0430 \u043e\u0442\u043c\u0435\u043d\u0435\u043d\u043d\u043e\u0435         val update = CancelledContinuation(this, cause, handled = state is CancelHandler || state is Segment&lt;*&gt;)         if (!_state.compareAndSet(state, update)) return@loop         \/\/ \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043e\u0442\u043c\u0435\u043d\u044b, \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0447\u0435\u0440\u0435\u0437          \/\/ invokeOnCancellation() \u043c\u0435\u0442\u043e\u0434         when (state) {             is CancelHandler -&gt; callCancelHandler(state, cause)             is Segment&lt;*&gt; -&gt; callSegmentOnCancellation(state, cause)         }         ...         return true     } }  override fun invokeOnCancellation(handler: CompletionHandler) =     \/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0432 CancellableContinuationImpl \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a,     \/\/ \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0439 \u043f\u0440\u0438 \u043e\u0442\u043c\u0435\u043d\u0435 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b     invokeOnCancellation(CancelHandler.UserSupplied(handler))<\/code><\/pre>\n<p>\u0421\u0443\u043c\u043c\u0438\u0440\u0443\u0435\u043c \u043a\u0430\u043a \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0442\u043c\u0435\u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>delay()<\/code>:<\/p>\n<ol>\n<li>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u0430\u043c\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 &#8212; \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u044e\u0442\u0441\u044f \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 <code>JobNode<\/code> \u0443\u0437\u043b\u044b \u0438\u0437 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u043e\u043d\u043e \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043d\u0430 <code>Finishing<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0434\u043e\u0447\u0435\u0440\u043d\u0435\u0433\u043e <code>JobNode<\/code> \u0443\u0437\u043b\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>JobNode.invoke()<\/code> \u043c\u0435\u0442\u043e\u0434 &#8212; <code>JobNode<\/code> \u0443\u0437\u043b\u044b \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u043e\u0432\u0441\u043a\u0438\u0435 <code>Job'\u044b<\/code>, \u043d\u043e \u0438 \u043d\u0430 <code>CancellableContinuation<\/code> \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, <code>CancellableContinuation<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>delay()<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 <code>JobNode.invoke()<\/code> \u0434\u043b\u044f <code>CancellableContinuation<\/code>, \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0437\u0432\u0430\u043d\u044b \u0432\u0441\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0447\u0435\u0440\u0435\u0437 <code>CancellableContinuation.invokeOnCancellation()<\/code> \u043c\u0435\u0442\u043e\u0434, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>delay()<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>delay()<\/code> \u043e\u0442\u043c\u0435\u043d\u0438\u0442 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0443 &#8212; \u0432 Android \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>Handler.removeCallbacks()<\/code> \u043c\u0435\u0442\u043e\u0434, \u043e\u043d \u0443\u0434\u0430\u043b\u0438\u0442 \u0437\u0430\u0434\u0430\u0447\u0443 \u0438\u0437 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430.<\/p>\n<\/li>\n<\/ol>\n<h2>\u041a\u0430\u043a \u043e\u0442\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f suspend \u0444\u0443\u043d\u043a\u0446\u0438\u0438<\/h2>\n<p>\u0412\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c \u0447\u0442\u043e \u043d\u0435 \u0432\u043e \u0432\u0441\u0435\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f\u0445 suspend \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043e\u0442\u043c\u0435\u043d\u0435\u043d\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0437\u0434\u0435\u0441\u044c \u044d\u0442\u043e \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e:<\/p>\n<pre><code class=\"kotlin\">suspend fun sleep() {     Thread.sleep(500) }  suspend fun welcome() {     println(\"Welcome!\") }  val job = launch(Dispatchers.IO) {     sleep()     welcome() }  delay(100)  \/\/ \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u0441\u044f, \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f sleep() \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 welcome() job.cancel()<\/code><\/pre>\n<p>\u0422\u0430\u043a \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043d\u0438 \u043e\u0434\u043d\u0430 \u0438\u0437 suspend \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u043d\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0438 \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043a\u043e\u0434 \u0432 suspend \u0431\u043b\u043e\u043a\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e. \u0415\u0441\u043b\u0438 \u0432\u044b \u0443\u0436\u0435 \u0437\u0430\u0431\u044b\u043b\u0438 \u0438\u0437 <a href=\"https:\/\/habr.com\/en\/articles\/827866\/\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438<\/a>, \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u044e \u0447\u0442\u043e \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e suspend \u0431\u043b\u043e\u043a\u0430, \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u043e\u0433\u043e \u0432 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 switch case, \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0442 \u0442\u0430\u043a\u0438\u043c:<\/p>\n<pre><code class=\"kotlin\">class GeneratedContinuationImplementation(...) : ... {      override fun resumeWith(result: Result&lt;Any?&gt;) {         val outcome: Result&lt;Any?&gt; =             try {                 \/\/ \u043f\u0440\u0438 \u0445\u043e\u0440\u043e\u0448\u043e \u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 suspend \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u0445,                 \/\/ \u043a\u0430\u0436\u0434\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u043a COROUTINE_SUSPENDED \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e                 \/\/ \u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442 \u0441\u0432\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043e\u043d\u0430 \u0432\u044b\u0437\u043e\u0432\u0435\u0442                  \/\/ Continuation.resumeWith() \u044d\u0442\u043e\u0433\u043e Continuation'\u0430 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f                  \/\/ \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f suspend \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432 switch case \u0431\u043b\u043e\u043a\u0435                 val outcome = invokeSuspend(param)                 if (outcome === COROUTINE_SUSPENDED) return                 Result.success(outcome)             } catch (exception: Throwable) {                 Result.failure(exception)         }         \/\/ \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f suspend \u0431\u043b\u043e\u043a\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0441\u044f \u0441\u0430\u043c\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430         coroutine.resumeWith(outcome)     }      fun sleep(cont: Continuation&lt;Any?&gt;): Any {         Thread.sleep(500)         \/\/ \u043d\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 COROUTINE_SUSPENDED,         \/\/ \u043a\u043e\u0434 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e         return Unit     }      fun welcome(cont: Continuation&lt;Any?&gt;): Any {         \/\/ \u0442\u0443\u0442 \u0442\u0430\u043a\u0436\u0435 \u043d\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438         println(\"Welcome!\")         return Unit     }      \/\/ \u044f \u0443\u0431\u0440\u0430\u043b switch case \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b, \u043b\u043e\u0433\u0438\u043a\u0430 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u0442\u0430\u043a\u0430\u044f \u0436\u0435     override fun invokeSuspend(result: Result&lt;Any?&gt;): Any {         \/\/ \u0442\u0430\u043a \u043a\u0430\u043a \u043d\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0432\u0441\u0435 \u043c\u0435\u0442\u043e\u0434\u044b          \/\/ \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0434\u0440\u0443\u0433 \u0437\u0430 \u0434\u0440\u0443\u0433\u043e\u043c         sleep(this)         welcome(this)         \/\/ \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 suspend \u0431\u043b\u043e\u043a\u0430         return result     }  }<\/code><\/pre>\n<p>\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u0435\u0440\u043d\u0438\u0442\u0435\u0441\u044c \u043a <a href=\"https:\/\/habr.com\/en\/articles\/827866\/\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435<\/a> \u0435\u0441\u043b\u0438 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u043e \u043f\u043e suspend \u0431\u043b\u043e\u043a\u0443, \u0442\u0430\u043c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u044d\u0442\u043e \u0440\u0430\u0437\u0436\u0435\u0432\u0430\u043d\u043e, \u043d\u0443 \u0430 \u043c\u044b \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043f\u043e\u0447\u0438\u043d\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u043a\u043e\u0434 \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u0441\u0442\u0430\u043b \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u043c\u044b\u043c:<\/p>\n<pre><code class=\"kotlin\">suspend fun sleep() {     \/\/ \u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u043b withContext \u0432\u044b\u0437\u043e\u0432     withContext(Dispatchers.IO) {         Thread.sleep(500)     } }  suspend fun welcome() {     println(\"Welcome!\") }  val job = launch {     sleep()     welcome() }  delay(100)  \/\/ \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e sleep(), \u0430 welcome() \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043c\u0435\u043d\u0435\u043d job.cancel()<\/code><\/pre>\n<p>\u0412\u0443\u0430\u043b\u044f! \u041c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 <code>withContext()<\/code> \u0432\u044b\u0437\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u0435\u0442 <code>DispatchedCoroutine<\/code>, \u0433\u0434\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f suspend \u0431\u043b\u043e\u043a \u0441 <code>Thread.sleep()<\/code> \u0432\u044b\u0437\u043e\u0432\u043e\u043c, \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u0430\u043a \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c:<\/p>\n<pre><code class=\"kotlin\">class GeneratedContinuationImplementation(...) : ... {      override fun resumeWith(result: Result&lt;Any?&gt;) {         val outcome: Result&lt;Any?&gt; =             try {                 \/\/ \u043f\u0440\u0438 \u0445\u043e\u0440\u043e\u0448\u043e \u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 suspend \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u0445,                 \/\/ \u043a\u0430\u0436\u0434\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u043a COROUTINE_SUSPENDED \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e                 \/\/ \u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442 \u0441\u0432\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043e\u043d\u0430 \u0432\u044b\u0437\u043e\u0432\u0435\u0442                  \/\/ Continuation.resumeWith() \u044d\u0442\u043e\u0433\u043e Continuation'\u0430 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f                  \/\/ \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f suspend \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432 switch case \u0431\u043b\u043e\u043a\u0435                 val outcome = invokeSuspend(param)                 if (outcome === COROUTINE_SUSPENDED) return                 Result.success(outcome)             } catch (exception: Throwable) {                 \/\/ \u0432\u043e\u0442 \u0442\u0443\u0442 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f CancellationException,                 \/\/ \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0441\u043b\u0438 \u0432\u044b \u043d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 \u0441\u0432\u043e\u0439 try \/ catch \u0432 suspend \u0431\u043b\u043e\u043a\u0435                 \/\/ \u0438 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0438\u0442\u0435 \u044d\u0442\u043e \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435, \u0443 \u0432\u0430\u0441 \u043c\u043e\u0436\u0435\u0442 \u0441\u043b\u043e\u043c\u0430\u0442\u044c\u0441\u044f                  \/\/ \u043e\u0442\u043c\u0435\u043d\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b                 Result.failure(exception)         }         \/\/ \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f suspend \u0431\u043b\u043e\u043a\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0441\u044f \u0441\u0430\u043c\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430         coroutine.resumeWith(outcome)     }      fun sleep(cont: Continuation&lt;Any?&gt;): Any {         \/\/ \u0441\u043e\u0437\u0434\u0430\u0435\u043c DispatchedCoroutine, \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u043e\u043d\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u0441\u044f         \/\/ \u043a\u0430\u043a \u0434\u043e\u0447\u0435\u0440\u043d\u044f\u044f Job'\u0430 \u0432 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0443         val coroutine = DispatchedCoroutine(...)         \/\/ \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u043d\u0435 \u0441\u0442\u0430\u043b \u0440\u0430\u0441\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u0434\u0438\u0441\u043f\u0430\u0442\u0447\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0438,          \/\/ \u043e\u043d\u0430 \u0435\u0441\u0442\u044c \u0432 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435\u00a0         coroutine.runSuspendBlockInIOThread {             \/\/ \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043a\u0430\u043a\u0443\u044e-\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0430 IO \u043f\u043e\u0442\u043e\u043a\u0435             Thread.sleep(500)             \/\/ \u0442\u0430\u043a\u0436\u0435 \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u043b \u043b\u043e\u0433\u0438\u043a\u0443 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043d\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439 \u043f\u043e\u0442\u043e\u043a             coroutine.runResumeInPreviousThread {                 \/\/ \u0432\u044b\u0445\u043e\u0434\u0438\u043c \u0438\u0437 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438                 \/\/ result \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f                  \/\/ DispatchedCoroutine                   cont.resumeWith(result)             }         }         \/\/ \u0434\u043e \u0432\u044b\u0437\u043e\u0432\u0430 cont.resumeWith() \u043c\u0435\u0442\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f          \/\/ \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438         return COROUTINE_SUSPENDED     }      fun welcome(cont: Continuation&lt;Any?&gt;): Any {         \/\/ \u044d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439         println(\"Welcome!\")         return Unit     }      var label = 0        override fun invokeSuspend(result: Result&lt;Any?&gt;): Any {         when(label) {             0 -&gt; {                 result.throwOnFailure()                 sleep(this)                 return COROUTINE_SUSPENDED             }             1 -&gt; {                 \/\/ result \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 CancellationException,                 \/\/ \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u043a\u0438\u043d\u0443\u0442\u044c\u0441\u044f \u0432\u044b\u0448\u0435 \u0438 \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435                 \/\/ suspend \u0431\u043b\u043e\u043a\u0430                 result.throwOnFailure()                 welcome()             }         }         return result     }  }<\/code><\/pre>\n<p>\u0412 \u0447\u0435\u043c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442\u043c\u0435\u043d\u0430? \u0414\u0430 \u0432\u0441\u0435 \u043f\u0440\u043e\u0441\u0442\u043e, \u043b\u044e\u0431\u0430\u044f suspend \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u043e\u0447\u0435\u0442 \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u0440\u0443\u0433\u0438\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0432 suspend \u0431\u043b\u043e\u043a\u0435 \u0434\u043e\u043b\u0436\u043d\u0430 \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0441 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c:<\/p>\n<pre><code class=\"kotlin\">fun welcome(continuation: Continuation&lt;Any&gt;): Any {     continuation.resumeWith(Result.failure(CancellationException(\"\u041e\u0442\u043c\u0435\u043d\u0438 suspend \u0431\u043b\u043e\u043a!\")))     return COROUTINE_SUSPENDED }<\/code><\/pre>\n<p>\u041a\u0430\u043a \u043c\u044b \u0443\u0436\u0435 \u0432\u044b\u044f\u0441\u043d\u0438\u043b\u0438 \u0442\u0430\u043a\u043e\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u0442\u0430\u043a\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438, \u0432 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 suspend \u0431\u043b\u043e\u043a \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a <code>Continuation<\/code>, \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0434\u043b\u044f suspend \u0431\u043b\u043e\u043a\u0430, \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0441 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c, \u043e\u043d \u0432\u044b\u0431\u0440\u043e\u0441\u0438\u0442 \u044d\u0442\u043e \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 \u0432\u044b\u0437\u043e\u0432 <code>Result.throwOnFailure()<\/code> \u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0433\u043e switch case \u0431\u043b\u043e\u043a\u0430.<\/p>\n<p>\u041e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0439\u0442\u0438 \u043c\u0435\u0441\u0442\u043e \u0433\u0434\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0441 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c, \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432\u043e\u0442 \u0442\u0443\u0442:<\/p>\n<pre><code class=\"kotlin\">fun sleep(cont: Continuation&lt;Any?&gt;): Any {     val coroutine = DispatchedCoroutine(...)     coroutine.runSuspendBlockInIOThread {         Thread.sleep(500)         coroutine.runResumeInPreviousThread {             \/\/ result \u0431\u0435\u0440\u0435\u0442\u0441\u044f \u0438\u0437 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f DispatchedCoroutine             \/\/ \u0438 \u043e\u043d \u043a\u0430\u043a \u0440\u0430\u0437 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 CancellationException, \u043a\u043e\u0433\u0434\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430             \/\/ \u0431\u044b\u043b\u0430 \u043e\u0442\u043c\u0435\u043d\u0435\u043d\u0430             cont.resumeWith(result)         }     }       return COROUTINE_SUSPENDED }  val job = launch {     \/\/ \u0432 sleep() \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f DispatchedCoroutine \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f      \/\/ \u043a\u0430\u043a \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0439 \u0443\u0437\u0435\u043b ChildHandleNode \u0432 \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0443     sleep() }  delay(100)  \/\/ \u043f\u0440\u0438 \u043e\u0442\u043c\u0435\u043d\u0435 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u043a\u0430\u043a \u0432\u044b \u0443\u0436\u0435 \u0437\u043d\u0430\u0435\u0442\u0435 \u0432\u0441\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u0443\u0437\u043b\u044b ChildHandleNode \/\/ \u0442\u043e\u0436\u0435 \u0431\u0443\u0434\u0443 \u043e\u0442\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f, \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e DispatchedCoroutine \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u0442 \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \/\/ Finishing, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0435\u0435 CancellationException, \u044d\u0442\u043e \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435  \/\/ \u0438 \u043f\u0440\u043e\u0431\u0440\u043e\u0441\u0438\u0442\u0441\u044f \u0432 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 Continuation \u0434\u043b\u044f suspend \u0431\u043b\u043e\u043a\u0430 job.cancel()<\/code><\/pre>\n<p>\u0412\u043e\u0442 \u0442\u0430\u043a\u0438\u043c \u043d\u0435\u0445\u0438\u0442\u0440\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0442\u043c\u0435\u043d\u0430 suspend \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u0445\u043e\u0442\u044f \u0441\u043a\u043e\u0440\u0435\u0435 suspend \u0431\u043b\u043e\u043a\u0430, \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0439\u0442\u0435 \u0447\u0442\u043e \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c\u0441\u044f \u043c\u043e\u0436\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 (\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 suspend \u0444\u0443\u043d\u043a\u0446\u0438\u0438) \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u0439.<\/p>\n<p>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u043c\u0430\u0433\u0438\u0438 \u043d\u0435\u0442.<\/p>\n<h2>Finishing \u044d\u0442\u043e \u043d\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b?<\/h2>\n<p>\u0418\u0437 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u043c\u044b \u0443\u0432\u0438\u0434\u0435\u043b\u0438 \u0447\u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u043e\u0442\u043c\u0435\u043d\u044b \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b, \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u0441\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 suspend \u0431\u043b\u043e\u043a\u0430, \u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432\u0435\u0440\u043d\u0435\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0432 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0443:<\/p>\n<pre><code class=\"kotlin\">class GeneratedContinuationImplementation(...) : ... {      override fun resumeWith(result: Result&lt;Any?&gt;) {         val outcome: Result&lt;Any?&gt; = ...         \/\/ \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0432 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0443         coroutine.resumeWith(outcome)     }      ... }<\/code><\/pre>\n<p>\u042d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043b\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u044e\u0449\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0438 \u043f\u0435\u0440\u0435\u0448\u043b\u0430 \u0432 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435:<\/p>\n<pre><code class=\"kotlin\">override fun resumeWith(result: Result&lt;T&gt;) {     val state = makeCompletingOnce(result.toState())     if (state === COMPLETING_WAITING_CHILDREN) return     afterResume(state) }  fun makeCompletingOnce(proposedUpdate: Any?): Any? {     loopOnState { state -&gt;         val finalState = tryMakeCompleting(state, proposedUpdate)         ...     } }  \/\/ \u044f \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u043b \u043b\u043e\u0433\u0438\u043a\u0443 \u0434\u043e \u043e\u0434\u043d\u043e\u0433\u043e tryMakeCompleting() \u043c\u0435\u0442\u043e\u0434\u0430, \/\/ \u0435\u0441\u043b\u0438 \u0445\u043e\u0442\u0438\u0442\u0435 \u0434\u043e\u0441\u043a\u043e\u043d\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432\u043e \u0432\u0441\u0435\u0445 \u043d\u044e\u0430\u043d\u0441\u0430\u0445  \/\/ \u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 JobSupport.tryMakeCompleting() fun tryMakeCompleting(state: Any?, result: Any?) {     if (state !is Incomplete) return COMPLETING_ALREADY      \/\/ \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 Job'\u044b     val list = getOrPromoteCancellingList(state) ?: return COMPLETING_RETRY      \/\/ \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u043e\u0435 \u0434\u043b\u044f \u043e\u0442\u043c\u0435\u043d\u044b \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0443\u0437\u043b\u043e\u0432     val finishing = state as? Finishing ?: Finishing(list, false, null)      \/\/ \u0442\u0443\u0442 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442\u0441\u044f \u0438\u0441\u043a\u044e\u0447\u0435\u043d\u0438\u0435 \u043b\u0438\u0431\u043e \u0438\u0437 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b state      \/\/ \u043b\u0438\u0431\u043e \u0438\u0437 \u043f\u0440\u0438\u0448\u0435\u0434\u0448\u0435\u0433\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 result, \u0435\u0433\u043e \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0431\u044b\u0442\u044c \u0435\u0441\u043b\u0438     \/\/ \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u0442\u0441\u044f \u0441\u0430\u043c\u0430 \u0431\u0435\u0437 \u043e\u0442\u043c\u0435\u043d \u0438 \u043e\u0448\u0438\u0431\u043e\u043a     val notifyRootCause: Throwable? = ...      \/\/ \u0435\u0441\u043b\u0438 \u043f\u0440\u0438\u0448\u043b\u043e \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043e\u0442\u043c\u0435\u043d\u044b \u0438\u043b\u0438 \u0432\u043d\u0435\u0448\u0442\u0430\u0442\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430      \/\/ \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 Job'\u044b      notifyRootCause?.let { notifyCancelling(list, it) }      \/\/ \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0436\u0434\u0430\u0442\u044c \u043f\u043e\u043a\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \/ \u043e\u0442\u043c\u0435\u043d\u044f\u0442\u0441\u044f \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b     val child = list.nextChild()     if (child != null &amp;&amp; tryWaitForChild(finishing, child, proposedUpdate))         return COMPLETING_WAITING_CHILDREN      \/\/ \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u044e\u0442\u0441\u044f \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435,      \/\/ \u043e\u0431\u044b\u0447\u043d\u043e \u0435\u0441\u043b\u0438 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u0442\u0441\u044f \u0448\u0442\u0430\u0442\u043d\u043e \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u0431\u0443\u0434\u0435\u0442:     \/\/ Unit \u0434\u043b\u044f launch \u043a\u043e\u0440\u0443\u0442\u0438\u043d,      \/\/ Any \u0434\u043b\u044f withContext \u043a\u043e\u0440\u0443\u0442\u0438\u043d,      \/\/ \u0435\u0441\u043b\u0438 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439 \/ \u043e\u0442\u043c\u0435\u043d\u043e\u0439 \u0442\u043e CompletedExceptionally     val finalException = ...     val finalState = ...             if (finalException != null) {         \/\/ \u0434\u043b\u044f \u043e\u0442\u043c\u0435\u043d\u044b cancelParent() \u0432\u0441\u0435\u0433\u0434\u0430 \u0432\u043e\u0437\u0440\u0430\u0449\u0430\u0435\u0442 true,         \/\/ \u0432 \u0441\u043b\u0443\u0447\u0430\u0435          \/\/ \u0432\u043d\u0435\u0448\u0442\u0430\u0442\u043d\u043e\u0433\u043e \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043e\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043e \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e          \/\/ \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f, \u0433\u0434\u0435 \u0432\u044b\u0437\u043e\u0432\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 handleJobException() \u0438         \/\/ \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 CoroutineExceptionHandler:         \/\/ \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d CoroutineExceptionHandler,         \/\/ \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u0440\u0430\u0448\u0438\u0442 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443 \u0441\u043e stacktrace'\u043e\u043c         val handled = cancelParent(finalException) || handleJobException(finalException)         if (handled) (finalState as CompletedExceptionally).makeHandled()     }      \/\/ \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435     _state.compareAndSet(state, finalState.boxIncomplete())            return finalState }<\/code><\/pre>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u0443 \u043d\u0435\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0434\u043d\u043e \u0438\u0437 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439:<\/p>\n<ol>\n<li>\n<p>Unit &#8212; \u0434\u043b\u044f \u0448\u0442\u0430\u0442\u043d\u043e\u0433\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d, \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0445 \u0447\u0435\u0440\u0435\u0437 launch \u0431\u0438\u043b\u0434\u0435\u0440 (<code>StandaloneCoroutine<\/code>).<\/p>\n<\/li>\n<li>\n<p><code>CompletedExceptionally<\/code> &#8212; \u0434\u043b\u044f \u043e\u0442\u043c\u0435\u043d\u0435\u043d\u043d\u043e\u0439 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u0438\u043b\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e\u0439 \u0432\u043d\u0435\u0448\u0442\u0430\u0442\u043d\u043e (\u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043e\u0442\u043b\u0438\u0447\u043d\u043e\u0435 \u043e\u0442 <code>CancellationException<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u041b\u044e\u0431\u043e\u0439 \u0434\u0440\u0443\u0433\u043e\u0439 \u0442\u0438\u043f &#8212; \u0434\u043b\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d, \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0445 \u0447\u0435\u0440\u0435\u0437 withContext \u0431\u0438\u043b\u0434\u0435\u0440 (<code>DispatchedCorotuine<\/code>).<\/p>\n<\/li>\n<\/ol>\n<p>\u0421 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c, \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u0430\u043a \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0434\u043e\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0441\u0432\u043e\u0438\u0445 \u0434\u0435\u0442\u0435\u0439, \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434:<\/p>\n<pre><code class=\"kotlin\">\/\/ \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 1 launch {     \/\/ \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 2     launch(Dispatchers.IO) {         ...     }     \/\/ \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 3     launch(Dispatchers.IO) {         ...     } }<\/code><\/pre>\n<p>\u041d\u0435 \u0441\u0435\u043a\u0440\u0435\u0442 \u0447\u0442\u043e \u0437\u0430\u043f\u0443\u0441\u043a \u043a\u043e\u0440\u0443\u0442\u0438\u043d 2 \u0438 3 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442 \u0431\u0435\u0437 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0442\u0430\u043a \u043a\u0430\u043a \u0442\u0443\u0442 \u043d\u0435 \u043d\u0430\u0434\u043e \u0434\u043e\u0436\u0438\u0434\u0430\u0442\u044c\u0441\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430, \u0430 \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442 \u0447\u0442\u043e suspend \u0431\u043b\u043e\u043a \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b 1 \u0441\u0440\u0430\u0437\u0443 \u0432\u0435\u0440\u043d\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 \u0432\u044b\u0437\u043e\u0432 <code>Continuation.resumeWith()<\/code>, \u0433\u0434\u0435 \u043a\u0430\u043a \u043c\u044b \u0443\u0436\u0435 \u0432\u044b\u044f\u0441\u043d\u0438\u043b\u0438 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0441\u044f. <\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 1 \u0434\u043e\u0436\u0434\u0430\u043b\u0430\u0441\u044c \u0434\u0435\u0442\u0435\u0439, \u0435\u0441\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430:<\/p>\n<pre><code class=\"kotlin\">fun tryMakeCompleting(state: Any?, result: Any?) {     ...        \/\/ \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0436\u0434\u0430\u0442\u044c \u043f\u043e\u043a\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \/ \u043e\u0442\u043c\u0435\u043d\u044f\u0442\u0441\u044f \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b     val child = list.nextChild()     if (child != null &amp;&amp; tryWaitForChild(finishing, child, proposedUpdate))         return COMPLETING_WAITING_CHILDREN      ...        \/\/ \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0434\u0435\u0442\u0435\u0439 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043f\u043e\u043c\u0435\u043d\u044f\u0435\u0442 \u0441\u0432\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435      \/\/ \u043d\u0430 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e\u0435     _state.compareAndSet(state, finalState.boxIncomplete())      ... }  private tailrec fun tryWaitForChild(state: Finishing, child: ChildHandleNode, proposedUpdate: Any?): Boolean {     \/\/ \u0432 \u0434\u043e\u0447\u0435\u0440\u043d\u044e\u044e Job'\u0443 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 CompletionHandler,     \/\/ \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0437\u043e\u0432\u0435\u0442\u0441\u044f \u043a\u043e\u0433\u0434\u0430 \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0442\u044c\u0441\u044f     val handle = child.childJob.invokeOnCompletion(         invokeImmediately = false,         handler = ChildCompletion(this, state, child, proposedUpdate)     )     \/\/ \u0435\u0441\u043b\u0438 \u0434\u043e\u0447\u0435\u0440\u043d\u044f\u044f Job'\u0430 \u0435\u0449\u0435 \u043d\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u0436\u0434\u0435\u043c     if (handle !== NonDisposableHandle) return true \/\/ child is not complete and we've started waiting for it     \/\/ \u0438\u043d\u0430\u0447\u0435 \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0434\u043e\u0447\u0435\u0440\u043d\u044e\u044e Job'\u0443     val nextChild = child.nextChild() ?: return false     return tryWaitForChild(state, nextChild, proposedUpdate) }  private class ChildCompletion(     private val parent: JobSupport,     private val state: Finishing,     private val child: ChildHandleNode,     private val proposedUpdate: Any? ) : JobNode() {     override val onCancelling get() = false     \/\/ \u043a\u043e\u0433\u0434\u0430 \u0434\u043e\u0447\u0435\u0440\u043d\u044f\u044f Job'\u0430 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0442\u044c\u0441\u044f \u043e\u043d\u0430 \u0432\u044b\u0437\u043e\u0432\u0435\u0442 \u044d\u0442\u043e\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a     override fun invoke(cause: Throwable?) {         \/\/ \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0442\u044c\u0441\u044f          parent.continueCompleting(state, child, proposedUpdate)     } }<\/code><\/pre>\n<p>\u0420\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0436\u0434\u0430\u0442\u044c \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0434\u0435\u0442\u0435\u0439 \u0438 \u043f\u043e\u043a\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0434\u043e\u0447\u0435\u0440\u043d\u044f\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043d\u0435 \u0432\u044b\u0437\u043e\u0432\u0435\u0442  <code>ChildCompletion.invoke()<\/code> \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u043e\u043d\u0430 \u043d\u0435 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u0442 \u0432 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435.<\/p>\n<p>P.S. \u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0447\u0443\u0432\u0430\u043a\u0443 <a class=\"mention\" href=\"\/users\/manwtein\">@manwtein<\/a> \u0447\u0442\u043e \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u043b \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0445 \u043f\u0440\u043e \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u043a\u043e\u0440\u0443\u0442\u0438\u043d \u0432 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u0435! <\/p>\n<h2>\u0418\u0442\u043e\u0433\u0438<\/h2>\n<p>\u0423\u0445, \u0434\u0443\u043c\u0430\u043b \u043d\u0435 \u0432\u044b\u0434\u0435\u0440\u0436\u0443 \u0434\u043e \u043a\u043e\u043d\u0446\u0430 \u044d\u0442\u043e\u0433\u043e \u0434\u043b\u0438\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430, \u043d\u043e \u0447\u0435\u043c \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c\u0441\u044f \u0432 \u041d\u043e\u0432\u043e\u0433\u043e\u0434\u043d\u0438\u0435 \u043f\u0440\u0430\u0437\u0434\u043d\u0438\u043a\u0438 \u0435\u0441\u043b\u0438 \u043d\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0443\u043f\u0435\u0440\u0441\u043b\u043e\u0436\u043d\u0443\u044e \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e?).<\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0434\u0432\u0435\u0434\u0435\u043c \u0438\u0442\u043e\u0433\u0438:<\/p>\n<ol>\n<li>\n<p><code>Job<\/code> &#8212; \u044d\u043b\u0435\u043c\u0435\u043d\u0442 <code>CoroutineContext'\u0430<\/code>, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0439 \u0437\u0430 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b: \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435, \u043e\u0442\u043c\u0435\u043d\u0430, \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435, \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439, \u0434\u043b\u044f lazy \u043a\u043e\u0440\u0443\u0442\u0438\u043d \u0435\u0441\u0442\u044c \u0435\u0449\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 &#171;\u043d\u0435 \u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f&#187;.  <\/p>\n<\/li>\n<li>\n<p>\u0412 <code>Job<\/code> \u0435\u0441\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 Boolean \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0434\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b: isActive &#8212; \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0438\u043b\u0438 \u043d\u0435\u0442, isCompleted &#8212; \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0438\u043b\u0438 \u043d\u0435\u0442, isCancelled &#8212; \u043e\u0442\u043c\u0435\u043d\u0435\u043d\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0438\u043b\u0438 \u043d\u0435\u0442.\u00a0<\/p>\n<\/li>\n<li>\n<p><code>JobSupport<\/code> &#8212; \u044d\u0442\u043e \u043e\u0434\u043d\u0430 \u0438\u0437 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0439 <code>Job'\u044b<\/code>, \u043e\u0442 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u044e\u0442\u0441\u044f \u0434\u0440\u0443\u0433\u0438\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a <code>SupervisorJob<\/code> \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440.<\/p>\n<\/li>\n<li>\n<p><code>JobSupport<\/code> \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e <code>Job'\u0443<\/code>, \u0435\u0441\u043b\u0438 \u0443 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u0435\u0441\u0442\u044c \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c, \u044d\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u043f\u0440\u043e\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u043d\u0438\u044f \u043e\u0442\u043c\u0435\u043d\u044b \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044e \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u043d\u0435\u0448\u0442\u0430\u0442\u043d\u043e\u0439 \u043e\u0442\u043c\u0435\u043d\u044b.<\/p>\n<\/li>\n<li>\n<p><code>JobSupport<\/code> \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0445\u0440\u0430\u043d\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 <code>Job\u2019\u044b<\/code> \u043f\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043b\u043e\u0433\u0438\u043a\u0435: \u0435\u0441\u043b\u0438 \u043d\u0435\u0442 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 <code>Job<\/code>, \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f <code>Empty<\/code> \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435; \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u043e\u0434\u043d\u0430 \u0434\u043e\u0447\u0435\u0440\u043d\u044f\u044f <code>Job'\u0430<\/code> \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f <code>JobNode<\/code> \u0443\u0437\u0435\u043b, \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 &#8212; <code>ChildHandleNode<\/code>; \u0435\u0441\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 <code>Job<\/code> \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 <code>NodeList<\/code>, \u0433\u0434\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 <code>JobNode<\/code> \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u043b\u0435\u0436\u0430\u0442 \u0432 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u043c \u0441\u043f\u0438\u0441\u043a\u0435.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043b\u0430\u0441\u0441 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b <code>StandaloneCoroutine<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430\u0441\u043b\u0435\u0434\u043d\u0438\u043a\u043e\u043c <code>JobSupport<\/code>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u0441\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0438\u0437 <code>JobSupport<\/code> \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0435.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u043c\u0435\u043d\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0448\u0442\u0430\u0442\u043d\u043e\u0439, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 <code>Job.cancel()<\/code>, \u0432 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0442\u043c\u0435\u043d\u044f\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b, \u043e\u0442\u043c\u0435\u043d\u0430 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044e.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u043c\u0435\u043d\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0432\u043d\u0435\u0448\u0442\u0430\u0442\u043d\u043e\u0439, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u0440\u0438 \u0432\u044b\u0431\u0440\u043e\u0441\u0435 \u043b\u044e\u0431\u043e\u0433\u043e \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043e\u0442\u043b\u0438\u0447\u043d\u043e\u0433\u043e \u043e\u0442 <code>CancellationException<\/code>, \u0432 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0442\u043c\u0435\u043d\u044f\u0442\u0441\u044f \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u0438 \u043e\u0442\u043c\u0435\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0431\u0440\u043e\u0448\u0435\u043d\u0430 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044e, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u043b\u0438\u0431\u043e \u043d\u0435 \u043f\u0440\u043e\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0442\u044c \u0434\u0430\u043b\u044c\u0448\u0435 \u043e\u0442\u043c\u0435\u043d\u0443 (\u0435\u0441\u043b\u0438 \u044d\u0442\u043e <code>SupervisorJob<\/code>), \u043b\u0438\u0431\u043e \u043f\u0440\u043e\u0431\u0440\u043e\u0441\u0438\u0442\u044c \u0435\u0435 \u0434\u043e \u0441\u0430\u043c\u043e\u0433\u043e \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f, \u0433\u0434\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043e <code>CoroutineExceptionHandler'\u043e\u043c<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d <code>CoroutineExceptionHandler<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u0440\u0430\u0448\u0438\u0442 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443 \u0441\u043e stacktrace&#8217;\u043e\u043c.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043e\u0442\u043c\u0435\u043d\u0430 \u043b\u043e\u0433\u0438\u043a\u0438 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0435 \u0432 \u0441\u0430\u043c\u043e\u0439 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0435, \u0430 \u0432 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 suspend \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u0445 \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a <code>delay()<\/code> \u0438\u043b\u0438 \u0432 suspend \u0431\u043b\u043e\u043a\u0430\u0445, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0445 \u0442\u0430\u043a\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f <code>delay()<\/code> \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 <code>CancellableContinuation<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0443 \u043a\u0430\u043a \u0434\u043e\u0447\u0435\u0440\u043d\u044f\u044f <code>Job'\u0430<\/code> \u0438 \u043f\u0440\u0438 \u043e\u0442\u043c\u0435\u043d\u0435 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u043c \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430\u043c \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f. \u0421\u0430\u043c\u0430\u044f \u0433\u043b\u0430\u0432\u043d\u0430\u044f \u0444\u0438\u0448\u043a\u0430 <code>CancellableContinuation<\/code> \u0432 \u0442\u043e\u043c \u0447\u0442\u043e \u043f\u0440\u0438 \u043e\u0442\u043c\u0435\u043d\u0435 \u043e\u043d \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438, \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0442\u043e\u0434 <code>CancellableContinuation.invokeOnCancellation()<\/code>, \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>delay()<\/code> \u0442\u0430\u043a\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u0442 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0443.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u043e\u0442 suspend \u0431\u043b\u043e\u043a \u0433\u0434\u0435 suspend \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0432 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438, \u0432 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043a\u043e\u0434 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f \u043a\u0430\u043a \u043e\u0434\u0438\u043d \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043c\u0435\u0442\u043e\u0434.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043e\u0442\u043c\u0435\u043d\u044b \u0438\u043b\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u043e\u043d\u0430 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442 \u0432 \u043e\u0434\u043d\u043e \u0438\u0437 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439: Unit &#8212; \u0434\u043b\u044f \u0448\u0442\u0430\u0442\u043d\u043e\u0433\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d, \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0445 \u0447\u0435\u0440\u0435\u0437 launch \u0431\u0438\u043b\u0434\u0435\u0440 (<code>StandaloneCoroutine<\/code>), <code>CompletedExceptionally<\/code> &#8212; \u0434\u043b\u044f \u043e\u0442\u043c\u0435\u043d\u0435\u043d\u043d\u043e\u0439 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u0438\u043b\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e\u0439 \u0432\u043d\u0435\u0448\u0442\u0430\u0442\u043d\u043e, \u043b\u044e\u0431\u043e\u0439 \u0434\u0440\u0443\u0433\u043e\u0439 \u0442\u0438\u043f &#8212; \u0434\u043b\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d, \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0445 \u0447\u0435\u0440\u0435\u0437 withContext \u0431\u0438\u043b\u0434\u0435\u0440 (<code>DispatchedCorotuine<\/code>).<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0441\u0441\u044b\u043b\u043a\u0438:<\/p>\n<ol>\n<li>\n<p><a href=\"https:\/\/t.me\/android_under_the_hood\" rel=\"noopener noreferrer nofollow\">\u041c\u043e\u0439 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c \u043a\u0430\u043d\u0430\u043b<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/t.me\/dimych_notes\" rel=\"noopener noreferrer nofollow\">\u041c\u043e\u0439 \u043b\u0438\u0447\u043d\u044b\u0439 \u0431\u043b\u043e\u0433 \u043e\u0431\u043e \u0432\u0441\u0435\u043c<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/en\/articles\/827866\/\" rel=\"noopener noreferrer nofollow\">\u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u043f\u043e \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430\u043c<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.youtube.com\/watch?v=YD2GeSEJQtI\" rel=\"noopener noreferrer nofollow\">\u041a\u0443\u0440\u0441 \u043f\u043e \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430\u043c \u043e\u0442 Android Broadcast<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/kotlinlang.org\/docs\/coroutines-overview.html\" rel=\"noopener noreferrer nofollow\">\u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043e\u043a\u0430<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.youtube.com\/watch?v=rB5Q3y73FTo\" rel=\"noopener noreferrer nofollow\">\u041a\u0440\u0443\u0442\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434 \u043e\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/github.com\/Kotlin\/kotlinx.coroutines\" rel=\"noopener noreferrer nofollow\">\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u043a\u043e\u0440\u0443\u0442\u0438\u043d<\/a><\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u0438\u0448\u0438\u0442\u0435 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0445 \u0432\u0430\u0448\u0435 \u043c\u043d\u0435\u043d\u0438\u0435 \u0438 \u0432\u0441\u0435\u043c \u0445\u043e\u0440\u043e\u0448\u0435\u0433\u043e \u043a\u043e\u0434\u0430!<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/873076\/\"> https:\/\/habr.com\/ru\/articles\/873076\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><\/figure>\n<p><a href=\"https:\/\/habr.com\/en\/articles\/827866\/\" rel=\"noopener noreferrer nofollow\">\u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435<\/a> \u044f \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c, \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0437\u0430\u043a\u0430\u043f\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0442\u0430\u043a\u0443\u044e \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c \u043a\u0430\u043a Job \u0438 \u043a\u0430\u043a \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u043e\u0442\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b, \u0432 \u043e\u0431\u0449\u0435\u043c \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u043f\u043e\u0433\u043d\u0430\u043b\u0438!<\/p>\n<h2>\u0417\u043d\u0430\u043a\u043e\u043c\u0438\u043c\u0441\u044f \u0441 Job \u0438 JobSupport <\/h2>\n<p>\u0427\u0435\u0440\u043a\u0430\u043d\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code class=\"kotlin\">\/\/ parent coroutine launch {      \/\/ child coroutine 1     launch {          ...     }     \/\/ child coroutine 2     launch {          ...     } }.cancel()<\/code><\/pre>\n<p>\u041f\u043e \u043b\u043e\u0433\u0438\u043a\u0435 <a href=\"https:\/\/kotlinlang.org\/docs\/coroutines-basics.html#structured-concurrency\" rel=\"noopener noreferrer nofollow\">Structured Concurrency<\/a> \u043e\u0442\u043c\u0435\u043d\u0430 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u0434\u043e\u043b\u0436\u043d\u0430 \u043f\u0440\u0438\u0432\u0435\u0437\u0442\u0438 \u043a \u043e\u0442\u043c\u0435\u043d\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u043a\u043e\u0440\u0443\u0442\u0438\u043d (1 \u0438 2), \u044d\u0442\u043e \u043e\u0434\u043d\u043e \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u043f\u0440\u0430\u0432\u0438\u043b \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430.<\/p>\n<p>\u041f\u0440\u043e\u0432\u0430\u043b\u0438\u043c\u0441\u044f \u0432 \u043c\u0435\u0442\u043e\u0434 <code>cancel()<\/code> \u0438 \u0443\u0437\u043d\u0430\u0435\u043c \u043a\u043e\u043c\u0443 \u043e\u043d \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0438\u0442: <\/p>\n<pre><code class=\"kotlin\">interface Job : CoroutineContext.Element {     \/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u043e\u0447\u0435\u0440\u043d\u044e\u044e Job      fun attachChild(child: ChildJob): ChildHandle        \/\/ \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u0442 Job     fun cancel(cause: CancellationException? = null) }<\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434 <code>cancel()<\/code> \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0438\u0442 \u0442\u0430\u043a\u043e\u0439 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043a\u0430\u043a <code>Job<\/code>, \u044d\u0442\u043e \u043e\u0434\u0438\u043d \u0438\u0437 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 <code>CoroutineContext'\u0430<\/code>, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0439 \u0437\u0430 \u043e\u0434\u043d\u043e \u0438\u0437 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b: <\/p>\n<ol>\n<li>\n<p>\u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f<\/p>\n<\/li>\n<li>\n<p>\u043e\u0442\u043c\u0435\u043d\u0435\u043d\u0430<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439<\/p>\n<\/li>\n<li>\n<p>\u0435\u0449\u0435 \u043d\u0435 \u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f (\u0435\u0441\u043b\u0438 \u044d\u0442\u043e <a href=\"https:\/\/kotlinlang.org\/api\/kotlinx.coroutines\/kotlinx-coroutines-core\/kotlinx.coroutines\/-coroutine-start\/-l-a-z-y\/\" rel=\"noopener noreferrer nofollow\">lazy \u0437\u0430\u043f\u0443\u0441\u043a \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b<\/a>)<\/p>\n<\/li>\n<\/ol>\n<p>\u0412 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435 <code>Job<\/code> \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0437\u0432\u0430\u0442\u044c <a href=\"https:\/\/en.wikipedia.org\/wiki\/Finite-state_machine\" rel=\"noopener noreferrer nofollow\">\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u043c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u043e\u043c<\/a> &#8212; \u0435\u0441\u0442\u044c \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 &#171;\u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f&#187; \u0438 \u0435\u0441\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b \u0432 \u0434\u0440\u0443\u0433\u0438\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u0440\u0438 \u0432\u044b\u0431\u0440\u043e\u0441\u0435 <code>CancellationException<\/code> \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u0442 \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 &#171;\u043e\u0442\u043c\u0435\u043d\u0435\u043d\u0430&#187; \u0438 \u0442\u0434.<\/p>\n<p>\u0421 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f\u043c\u0438 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c, \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 <code>Job<\/code>, \u043e\u043d\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0432 <code>JobSupport<\/code>, \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c, \u0442\u0430\u043a\u0436\u0435 \u044d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0441\u0430\u043c\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430:<\/p>\n<pre><code class=\"kotlin\">abstract class AbstractCoroutine&lt;in T&gt;(     parentContext: CoroutineContext,     initParentJob: Boolean,     active: Boolean ) : JobSupport(active), Job, Continuation&lt;T&gt;, CoroutineScope { ... }<\/code><\/pre>\n<p>\u041a\u043b\u0430\u0441\u0441 <code>JobSupport<\/code> \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u043e\u0439, \u0431\u043e\u043b\u0435\u0435 1000 \u0441\u0442\u0440\u043e\u043a \u043a\u043e\u0434\u0430, \u043d\u043e \u043d\u0430\u0441 \u043f\u043e\u043a\u0430 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u0430 <code>cancel()<\/code>:<\/p>\n<pre><code class=\"kotlin\">\/\/ \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0432 JobSupport override fun cancel(cause: CancellationException?) {     cancelInternal(cause ?: defaultCancellationException()) }  \/\/ \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 cancelInternal() \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \/\/ \u043b\u043e\u0433\u0438\u043a\u0438 \u043e\u0442\u043c\u0435\u043d\u044b \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430\u0445, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0432 ChannelCoroutine open fun cancelInternal(cause: Throwable) {     cancelImpl(cause) }  \/\/ \u0434\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d \u0431\u0430\u0437\u043e\u0432\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u043e\u0442\u043c\u0435\u043d\u044b \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0442\u0443\u0442 internal fun cancelImpl(cause: Any?): Boolean {     var finalState: Any? = COMPLETING_ALREADY     if (onCancelComplete) {         \/\/ \u0442\u0443\u0442 \u043b\u043e\u0433\u0438\u043a\u0430 \u0442\u043e\u043a\u043e \u0434\u043b\u044f CompletableDeferred \u043a\u043e\u0440\u0443\u0442\u0438\u043d,          \/\/ \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0432 \u043d\u0438\u0445 \u0443\u0433\u043b\u0443\u0431\u043b\u044f\u0442\u044c\u0441\u044f     }          if (finalState === COMPLETING_ALREADY) {         \/\/ \u043d\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 \u044d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434         finalState = makeCancelling(cause)     }     \/\/ \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c true, \u0435\u0441\u043b\u0438 \u043e\u0442\u043c\u0435\u043d\u0430 \u0443\u0434\u0430\u043b\u0430\u0441\u044c      \/\/ \u0438\u043b\u0438 false \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043a\u0430\u043a\u0430\u044f-\u0442\u043e \u0444\u0438\u0433\u043d\u044f     return when {         finalState === COMPLETING_ALREADY -&gt; true         finalState === COMPLETING_WAITING_CHILDREN -&gt; true         finalState === TOO_LATE_TO_CANCEL -&gt; false         else -&gt; {             afterCompletion(finalState)             true         }     } }  \/\/ \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0442\u043c\u0435\u043d\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b private fun makeCancelling(cause: Any?): Any? {     var causeExceptionCache: Throwable? = null \/\/ lazily init result of createCauseException(cause)     loopOnState { state -&gt;         when (state) {             ...             \/\/ Incomplete \u044d\u0442\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b             is Incomplete -&gt; {                 val causeException = causeExceptionCache ?: createCauseException(cause).also { causeExceptionCache = it }                 if (state.isActive) {                     \/\/ \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0442\u043c\u0435\u043d\u044b \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b, \u043d\u0430\u0448 \u0441\u043b\u0443\u0447\u0430\u0439                     if (tryMakeCancelling(state, causeException)) return COMPLETING_ALREADY                 } else {                     \/\/ \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b (\u043d\u0435 \u043e\u0442\u043c\u0435\u043d\u0430)                     val finalState = tryMakeCompleting(state, CompletedExceptionally(causeException))                     when {                         finalState === COMPLETING_ALREADY -&gt; error(\"Cannot happen in $state\")                         finalState === COMPLETING_RETRY -&gt; return@loopOnState                         else -&gt; return finalState                     }                 }             }             else -&gt; return TOO_LATE_TO_CANCEL \/\/ already complete         }     } }<\/code><\/pre>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0438\u0434\u0442\u0438 \u0434\u0430\u043b\u044c\u0448\u0435 \u0445\u043e\u0442\u0435\u043b \u0431\u044b \u0443\u0442\u043e\u0447\u043d\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442:<\/p>\n<ol>\n<li>\n<p><code>COMPLETING_ALREADY<\/code> &#8212; \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0443\u0436\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430.<\/p>\n<\/li>\n<li>\n<p><code>COMPLETING_WAITING_CHILDREN<\/code> &#8212; \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043e\u0436\u0438\u0434\u0430\u0435\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0434\u0435\u0442\u0435\u0439.<\/p>\n<\/li>\n<li>\n<p><code>COMPLETING_RETRY<\/code> &#8212; \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043d\u0435 \u0441\u043c\u043e\u0433\u043b\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0441\u044f \u0438 \u043d\u0430\u0434\u043e \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0435\u0449\u0435 \u0440\u0430\u0437.<\/p>\n<\/li>\n<li>\n<p><code>TOO_LATE_TO_CANCEL<\/code> &#8212; \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043f\u043e\u0437\u0434\u043d\u043e \u0434\u043b\u044f \u043e\u0442\u043c\u0435\u043d\u044b \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b.<\/p>\n<\/li>\n<\/ol>\n<p>\u042d\u0442\u043e \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u0435\u0442\u043e\u0434 <code>cancelImpl<\/code> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u044e\u0449\u0435\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 (\u0435\u0441\u043b\u0438 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b\u0430\u0441\u044c):<\/p>\n<pre><code class=\"kotlin\">internal fun cancelImpl(cause: Any?): Boolean {     val finalState = ...        return when {         finalState === COMPLETING_ALREADY -&gt; true         finalState === COMPLETING_WAITING_CHILDREN -&gt; true         finalState === TOO_LATE_TO_CANCEL -&gt; false         else -&gt; {             afterCompletion(finalState)             true         }     } }<\/code><\/pre>\n<p><strong>\u0412\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442<\/strong>: \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043d\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 <code>Job'\u0435<\/code>, \u0430 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u0430 \u043b\u0435\u0442\u0443 \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a <code>cancel()<\/code> \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440.<\/p>\n<p>\u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u0430\u043a\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 <code>Job'\u0435<\/code> \u0438 \u043a\u0430\u043a \u043e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u044b.<\/p>\n<h2>\u0423\u0433\u043b\u0443\u0431\u043b\u044f\u0435\u043c\u0441\u044f \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f JobSupport<\/h2>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0437\u0430\u0447\u0435\u043c \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0443\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0434\u043b\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b:<\/p>\n<pre><code class=\"kotlin\">class Thread1 : Thread() {      private var isRunning = false      val isActive: Boolean         get() = isRunning          override fun run() {         isRunning = true         while (true) {             \/\/ \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0446\u0438\u043a\u043b \u043f\u043e\u043a\u0430 isRunning \u0440\u0430\u0432\u0435\u043d true             if (!isRunning) break             ...         }     }          fun cancel() {           \/\/ \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u043c \u0446\u0438\u043a\u043b         isRunning = false     }    }<\/code><\/pre>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043f\u043e\u0442\u043e\u043a <code>Thread1<\/code> \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043c\u0435\u043d\u0435\u043d, \u043b\u043e\u0433\u0438\u043a\u0430 \u0432\u043d\u0443\u0442\u0440\u0438 \u043d\u0435\u0433\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0441\u044f, \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u0442\u0430\u043d\u0435\u0442 \u043d\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u043c, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e:<\/p>\n<ol>\n<li>\n<p>\u0423\u0437\u043d\u0430\u0442\u044c \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b\u0441\u044f \u043f\u043e\u0442\u043e\u043a \u0438\u043b\u0438 \u043d\u0435\u0442.<\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0434\u043b\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f (\u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u0446\u0438\u043a\u043b).<\/p>\n<\/li>\n<\/ol>\n<p>\u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0434\u043b\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d, \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u0437\u043d\u0430\u0442\u044c \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u043e\u0439 \u0432 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043a\u0430\u043a\u0443\u044e-\u0442\u043e \u043b\u043e\u0433\u0438\u043a\u0443 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f.<\/p>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0441\u0430\u043c\u044b\u0435 \u0447\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0432 <code>JobSupport<\/code>:<\/p>\n<pre><code class=\"kotlin\">\/\/ \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u0430 \u043b\u0435\u0442\u0443 (\u043d\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 JobSupport) val COMPLETING_ALREADY = Symbol(\"COMPLETING_ALREADY\") val COMPLETING_WAITING_CHILDREN = Symbol(\"COMPLETING_WAITING_CHILDREN\") val COMPLETING_RETRY = Symbol(\"COMPLETING_RETRY\") val TOO_LATE_TO_CANCEL = Symbol(\"TOO_LATE_TO_CANCEL\")  \/\/ \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0435\u0439 \u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 EMPTY_ACTIVE val EMPTY_NEW = Empty(false) \/\/ \u0434\u043b\u044f lazy \u043a\u043e\u0440\u0443\u0442\u0438\u043d val EMPTY_ACTIVE = Empty(true) \/\/ \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u043a\u043e\u0440\u0443\u0442\u0438\u043d  \/\/ \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0432 \u0441\u0442\u0430\u0442\u0443\u0441\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0435\u0442 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u043a\u043e\u0440\u0443\u0442\u0438\u043d class Empty(override val isActive: Boolean) : Incomplete { ... }  \/\/ \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0442\u043e\u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u0447\u0442\u043e \u0438 Empty, \u0442\u043e\u043a\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \/\/ \u0441\u043f\u0438\u0441\u043e\u043a CompletionHandler'\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0437\u0432\u0430\u043d\u044b \u043f\u0440\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b class InactiveNodeList(     override val list: NodeList ) : Incomplete { ... }  \/\/ \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0432 \u0441\u0442\u0430\u0442\u0443\u0441\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0435\u0441\u0442\u044c \u043e\u0434\u043d\u0430 \u0434\u043e\u0447\u0435\u0440\u043d\u044f\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 class ChildHandleNode(     val childJob: ChildJob ) : JobNode(), ChildHandle { ... }  \/\/ \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0432 \u0441\u0442\u0430\u0442\u0443\u0441\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0435\u0441\u0442\u044c \u0431\u043e\u043b\u0435\u0435  \/\/ \u0447\u0435\u043c \u043e\u0434\u043d\u0430 \u0434\u043e\u0447\u0435\u0440\u043d\u044f\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 class NodeList : LockFreeLinkedListHead(), Incomplete { ... }  \/\/ \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0432 \u0441\u0442\u0430\u0442\u0443\u0441\u0435 \u043e\u0442\u043c\u0435\u043d\u044b \u0438\u043b\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \/\/ \u044d\u0442\u043e \u043d\u0435 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043e\u0431 \u044d\u0442\u043e\u043c \u0435\u0449\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0440\u0430\u0437\u0434\u0435\u043b class Finishing(     override val list: NodeList,     isCompleting: Boolean,     rootCause: Throwable? ) : SynchronizedObject(), Incomplete { ... }  \/\/ \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0431\u044b\u043b\u0430 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u043f\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u0432\u044b\u0431\u0440\u043e\u0441\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f:  \/\/ 1) CancellationException, \u0435\u0441\u043b\u0438 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0431\u044b\u043b\u0430 \u043e\u0442\u043c\u0435\u043d\u0435\u043d\u0430 \/\/ 2) \u043b\u044e\u0431\u044b\u0435 \u0434\u0440\u0443\u0433\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \/\/ \u044d\u0442\u043e \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043e\u0431 \u044d\u0442\u043e\u043c \u0435\u0449\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0440\u0430\u0437\u0434\u0435\u043b class CompletedExceptionally(val cause: Throwable) { ... }  \/\/ JobSupport \u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0432 atomic \u0442\u0438\u043f\u0435 \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u0438\u0442\u044c  \/\/ \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0443 \u043e\u0442 \u043e\u0448\u0438\u0431\u043e\u043a \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438 (race condition) val _state = atomic&lt;Any?&gt;(if (active) EMPTY_ACTIVE else EMPTY_NEW)<\/code><\/pre>\n<p>\u0412 <code>JobSupport'\u0435<\/code> \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0438\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0434\u043d\u043e \u0438\u0437 \u0432\u044b\u0448\u0435\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0445. <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0432 \u043f\u0440\u0438\u043a\u043b\u0430\u0434\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u044b, \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c\u0438 Boolean \u043f\u043e\u043b\u044f\u043c\u0438:<\/p>\n<pre><code class=\"kotlin\">\/\/ \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0432 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0435, \u0442\u0430\u043a \u043a\u0430\u043a \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442 JobSupport class JobSupport : Job {      \/\/ \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0438\u043b\u0438 \u043d\u0435\u0442     override val isActive: Boolean get() {         val state = this.state         return state is Incomplete &amp;&amp; state.isActive     }      \/\/ \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0438\u043b\u0438 \u043d\u0435\u0442 (\u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435)     override val isCompleted: Boolean get() {         return state !is Incomplete     }      \/\/ \u043e\u0442\u043c\u0435\u043d\u0435\u043d\u0430 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430 \u0438\u043b\u0438 \u043d\u0435\u0442     override val isCancelled: Boolean get() {         val state = this.state         return state is CompletedExceptionally || (state is Finishing &amp;&amp; state.isCancelling)     }    }<\/code><\/pre>\n<p>\u0414\u0443\u043c\u0430\u044e \u0432\u044b \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u043e\u0434\u043d\u043e \u0438\u0437 \u043d\u0438\u0445, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0432\u044b\u0437\u044b\u0432\u0430\u043b\u0438 <code>Job.ensureActive()<\/code> \u043c\u0435\u0442\u043e\u0434:<\/p>\n<pre><code class=\"kotlin\">fun Job.ensureActive(): Unit {     if (!isActive) throw getCancellationException() }<\/code><\/pre>\n<p>\u0421 <code>JobSupport<\/code> \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\u043c\u0438 \u0431\u043e\u043b\u0435\u0435 \u043c\u0435\u043d\u0435\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c, \u043c\u043e\u0436\u0435\u043c \u0441\u043d\u043e\u0432\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u043b\u043e\u0433\u0438\u043a\u0435:<\/p>\n<pre><code class=\"kotlin\">internal fun cancelImpl(cause: Any?): Boolean {     ...     val finalState = makeCancelling(cause)     ... }  private fun makeCancelling(cause: Any?): Any? {     when (state) {         ...         is Incomplete -&gt; tryMakeCancelling(state, causeException)     } }                <\/code><\/pre>\n<p>\u042f \u0443\u0436\u0435 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u043b \u043a\u043e\u0434 \u044d\u0442\u0438\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432, \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439 \u0440\u0430\u0437\u0434\u0435\u043b \u0435\u0441\u043b\u0438 \u0435\u0433\u043e \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u043b\u0438, \u0433\u043b\u0430\u0432\u043d\u043e\u0435 \u043f\u043e\u043d\u044f\u0442\u044c \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u0432\u044b\u0437\u043e\u0432\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u0438 \u043e\u0442\u043c\u0435\u043d\u0435:<\/p>\n<blockquote>\n<p>cancel() \u2192 cancelInternal() \u2192 cancelImpl() \u2192 makeCancelling() \u2192 tryMakeCancelling()<\/p>\n<\/blockquote>\n<p>\u041f\u043e \u0438\u0442\u043e\u0433\u0443 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 <code>JobSupport.tryMakeCancelling()<\/code>, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u043e\u0432\u0430\u043b\u0438\u043c\u0441\u044f \u0442\u0443\u0434\u0430:<\/p>\n<pre><code class=\"kotlin\">private fun<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-444789","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/444789","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=444789"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/444789\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=444789"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=444789"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=444789"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}