Skip to content

Threading-Safe Objects For Swift.

License

Notifications You must be signed in to change notification settings

Pulichev/Threading

 
 

Repository files navigation

Threading

Threading provides a collection of thread-safe objects implemented purly in Swift. The objects are designed to be as easy to use as the native swift objects, but with an underlying implementation that is designed for concurrent reading and writing.

This library was inspired by this blog post by Basem Emara.

Table of Contents

Installation

To install using Swift Package Manager, simply include the following line in your Package.swift file under dependencies. Don't forget to add the dependency "Threading" to any targets that require the library.

.package(url: "https://github.com/Miraion/Threading.git", from: "1.0.0"),

Then simply add the following import statement to your source files.

import Threading

Usage

Common

Most threaded objects take an optional ThreadingType enum parameter in their initializers. This parameter tells the object how it should behave when being interacted with. There are two options: ThreadingType.serial where only one thread can use the object at a time, and ThreadingType.concurrent (default) where multiple threads can read from the object at a time, but when being mutated, only one thread can have access.

All threaded objects extend the generic ThreadedObject<T> base class which wraps around an object and provides thread-safe interfaces for interacting with said object. These three methods, async, sync and mutableSync, act as the interfaces through which the underlying (threaded) object may be viewed.

The async method acts as a mutable interface for the theaded object. The theaded object is passed as an inout parameter to a given closure which is executed concurrently along side the calling thread. Any actions that mutate the threaded object should be done asynchronously to ensure that no other thread is trying to access the threaded object at the same time.

async(_ callback: @escaping (inout T) -> Void)

The sync method is a readonly interface for the threaded object. This method is executed within the calling thread which allows values to be returned from this method. Only non-mutating methods may be called from within this method as there is no guarentee that the calling thread is the only viewer of the threaded object.

sync<ReturnType>(_ callback: @escaping (T) -> ReturnType) -> ReturnType

A third interface, mutatingSync, is a mutable interface that is executed within the calling thread. This method should be used when an action needs to both write and return a value from the underlying object: for example, the 'pop' action of a stack.

mutatingSync<ReturnType>(_ callback: @escaping (inout T) -> ReturnType) -> ReturnType

Atomic

The Atomic<T> class is a thread-safe container that holds a single object. The object can be interacted with using the sync and async methods described above or special load and store methods that are built specifically for this class.

Methods


func load() -> T

A synchronous read method that returns a copy of the threaded object.


func store(_ newElement: T)

An asynchronous write method that stores a brand new value in the atomic object.


func loading(_ action: @escaping (inout T) -> Void)

Performs an action on the underlying value asynchronously.


Example

let atomicFlag = Atomic<Bool>(true)

DispatchQueue.main.async {
    while atomicFlag.load() {
        print("From Async Thread")
        sleep(1)
    }
}

sleep(5)
atomicFlag.store(false)

ThreadedArray

ThreadedArray<T>, as the name implies, is a thread-safe, random access array. A majority of Swift's standard array methods are incorperated into this object to make it as easy to use as possible.

ThreadedArray conforms to the Collection protocol; meaning that can be used in for in loops.

Types

typealias InternalCollectionType = [T]
typealias Element = InternalCollectionType.Element
typealias Index = InternalCollectionType.Index

Methods


subscript(position: Int) -> T { get, set }

Random read/write access to any element in the array. Gets are performed synchronously while sets are performed asynchronously.


func append(_ newElement: T)

Asynchronously appends a new element to the end of the array.


func remove(at position: Int, callback: ((T) -> Void)? = nil)

Removes an element at a given position and passes that element to an optional closure which is executed asynchronously on the main thread after the element is removed.


ThreadedDictionary

ThreadedDictionary<K, V> is a thread-safe wrapper class for Swift's standard dictionary. A majority of the methods present in the standard dictionary are present in ThreadedDictionary.

ThreadedDictionary conforms to the Collection protocol; meaning that it can be used in for in loops.

Types

typealias InternalCollectionType = [K : V]
typealias Index = InternalCollectionType.Index
typealias Element = InternalCollectionType.Element
typealias Keys = InternalCollectionType.Keys
typealias Values = InternalCollectionType.Values

Methods


subscript(key: K) -> V? { get, set }

Key style subscript. Gets are performed synchronously while sets are perfomed asynchronously.


var keys: Keys { get }
var values: Values { get }

Returns the keys/values of the dictionary as a collection.


ThreadedQueue

ThreadedQueue<T> is a thread-safe wrapper for the LinkedQueue<T> class which comes with this library. It is a linked list style implementation of a queue which provides insertions and removals that are O(1).

Types

typealias InternalCollectionType = LinkedQueue<T>
typealias Element = InternalCollectionType.Element

Methods


func enqueue(_ newElement: T)

Asynchronously adds an element to the end of the queue.


func dequeue() -> Element

Synchronously removes and returns the first element of the queue. This method should not be called on an empty queue.

Uses the mutatingSync interface.


func safeDequeue() -> Element?

A safe version of dequeue that can be called on an empty queue. This method should be used instead of the regular dequeue when multiple threads are simultaneously removing elements from the queue.


var isEmpty: Bool { get }

Returns true if the queue is empty, false otherwise.


var count: Int { get }

Returns the number of elements in the queue.


About

Threading-Safe Objects For Swift.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Swift 100.0%