Skip to content

ben-smith-dev/swift-thread-local

Repository files navigation

swift-thread-local

supported swift versions supported platforms code coverage

A Swift package providing thread-local value wrappers.

Overview

Thread-local value wrappers give threads their own independent instance of the wrapped value. Setting or mutating one thread's value has no effect on another thread's value.

The defaultValue (or value for ReadonlyThreadLocal) passed into the wrapper's initializer is evaluated lazily at most once per thread. This ensures each thread has its own distinct value.

Thread-local wrapper method calls are restricted to synchronous contexts only. This ensures that no suspension points are hit, which may cause executer switches.

Important

Thread-local wrappers must be nonisolated and declared as global constants or static properties to avoid unexpected behavior and memory leaks.

ThreadLocal

Use ThreadLocal when the wrapped value can be read and overwritten arbitrarily, such as tracking a count.

import ThreadLocal

nonisolated let currentCount = ThreadLocal(defaultValue: 0)

// Get the current thread's wrapped value.
let count: Int = currentCount.get()

// Set the current thread's wrapped value.
currentCount.set(count + 1)

ScopedThreadLocal

Use ScopedThreadLocal when the wrapped value is temporarily scoped to synchronous operations, such as passing a context object down the call stack.

import ThreadLocal

nonisolated let currentContext = ScopedThreadLocal(defaultValue: Context())

// Get the current thread's scoped wrapped value (for global scope, returns the 'defaultValue').
let context: Context = currentContext.get()

// Set thread-local value for the duration of a synchronous operation (scope).
currentContext.withValue(context.withName("John Doe")) {
    // Calling 'currentContext.get()' will return the scoped value.  
}

// The thread-local value will be reverted back to 'context' automatically after the operation. 

ReadonlyThreadLocal

Use ReadonlyThreadLocal when the wrapped value does not need to be overwritten, such as a thread-local cache.

import ThreadLocal

nonisolated let currentCache = ReadonlyThreadLocal(value: Cache())

// Get the current thread's wrapped value.
let cache: Cache = currentCache.get()

Installation

Swift Package Manager (SPM)

Add the swift-thread-local SPM package to your package's dependency list:

dependencies: [
    .package(url: "https://github.com/ben-smith-dev/swift-thread-local", from: "1.0.0"),
]

Then add the ThreadLocal product to a target's dependency list:

dependencies: [
    .product(name: "ThreadLocal", package: "swift-thread-local"),
]

Xcode

Add swift-thread-local to your project as a package dependency.

Privacy

This package does not collect data or use required reason APIs.

Apple's privacy requirements

Contributing

This project is currently not accepting Pull Requests.

However, feedback is welcome! Please feel free to open an issue to report bugs, suggest improvements, or discuss feature requests.

License

This package is available under the MIT license, see LICENSE for details.

About

A Swift package providing thread-local value wrappers.

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages