From 0b91810d48522ccc4f49e39f448dfbfc772375c9 Mon Sep 17 00:00:00 2001 From: Vsevolod Tolstopyatov Date: Wed, 27 Feb 2019 17:38:09 +0300 Subject: [PATCH 1/2] Clarify thread locals documentation Fixes #985 --- .../jvm/src/ThreadContextElement.kt | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt b/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt index 68098f3829..f55edc4128 100644 --- a/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt +++ b/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt @@ -81,9 +81,11 @@ public interface ThreadContextElement : CoroutineContext.Element { * Wraps [ThreadLocal] into [ThreadContextElement]. The resulting [ThreadContextElement] * maintains the given [value] of the given [ThreadLocal] for coroutine regardless of the actual thread its is resumed on. * By default [ThreadLocal.get] is used as a value for the thread-local variable, but it can be overridden with [value] parameter. + * Beware that context element **does not track** modifications of the thread-local and accessing thread-local from coroutine + * without corresponding context element returns **undefined** value. See the examples for a detailed description. * - * Example usage looks like this: * + * Example usage: * ``` * val myThreadLocal = ThreadLocal() * ... @@ -97,7 +99,7 @@ public interface ThreadContextElement : CoroutineContext.Element { * println(myThreadLocal.get()) // Prints "null" * ``` * - * Note that the context element does not track modifications of the thread-local variable, for example: + * The context element does not track modifications of the thread-local variable, for example: * * ``` * myThreadLocal.set("main") @@ -109,12 +111,27 @@ public interface ThreadContextElement : CoroutineContext.Element { * ``` * * Use `withContext` to update the corresponding thread-local variable to a different value, for example: - * * ``` * withContext(myThreadLocal.asContextElement("foo")) { * println(myThreadLocal.get()) // Prints "foo" * } * ``` + * + * Accessing thread-local without corresponding context element leads to undefined value: + * ``` + * val tl = ThreadLocal.withInitial { "initial" } + * + * runBlocking { + * println(tl.get()) // Will print "initial" + * // Change context + * withContext(tl.asContextElement("modified")) { + * println(tl.get()) // Will print "modified" + * } + * // Context is changed again + * println(tl.get()) // <- WARN: can print either "modified" or "initial" + * } + * ``` + * to fix this behaviour use `runBlocking(tl.asContextElement())` */ public fun ThreadLocal.asContextElement(value: T = get()): ThreadContextElement = ThreadLocalElement(value, this) From c74e0ad4d2ab53a09e9024e3b3e14812a011c198 Mon Sep 17 00:00:00 2001 From: Vsevolod Tolstopyatov Date: Fri, 1 Mar 2019 15:59:53 +0300 Subject: [PATCH 2/2] Typos fixed --- kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt b/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt index f55edc4128..f83ced2caa 100644 --- a/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt +++ b/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt @@ -82,7 +82,7 @@ public interface ThreadContextElement : CoroutineContext.Element { * maintains the given [value] of the given [ThreadLocal] for coroutine regardless of the actual thread its is resumed on. * By default [ThreadLocal.get] is used as a value for the thread-local variable, but it can be overridden with [value] parameter. * Beware that context element **does not track** modifications of the thread-local and accessing thread-local from coroutine - * without corresponding context element returns **undefined** value. See the examples for a detailed description. + * without the corresponding context element returns **undefined** value. See the examples for a detailed description. * * * Example usage: @@ -117,7 +117,7 @@ public interface ThreadContextElement : CoroutineContext.Element { * } * ``` * - * Accessing thread-local without corresponding context element leads to undefined value: + * Accessing the thread-local without corresponding context element leads to undefined value: * ``` * val tl = ThreadLocal.withInitial { "initial" } *