A Modern Concurrency and Synchronization for Swift.

Related tags

Concurrency Safe
Overview


Swift 2.2 Platforms OS X | iOS | Linux

##Features

  • Simple Atomic class for numbers and strings.
  • Uncomplicated dispatch keyword for firing off background routines.
  • Awesome Chan for concurrent communication.
  • Useful sync APIs. Mutex, Cond, Once, WaitGroup

Atomic

Types

Int, Int8, Int16, Int32, Int64, UInt, UInt8, UInt16, UInt32, UInt64, Float, Double, Bool, String

Operators

==, !=, &&, ||, <=, >=, >, <, !
+, -, *, /, %, <<, >>, ^, &, &+, &-, &*, ++, --, +=, -=, *=, /=, %=, +=, <<=, >>=, ^=, &=

var anum = IntA(100)      // IntA is an alias for Atomic.
anum += 15                // Adds a value atomically.
let res = anum % 4        // Modulo operation atomically.
print("\(anum) \(res)")   // prints '115 3'.

Dispatch

Safe adds an uncomplicated method for dispatching routines.

dispatch {
    print("Background")
}
print("Foreground")

Channels

A new Chan class provides a clean and simple model for concurrently sharing objects. Chan is modeled after Go channels.

Sharing Memory by Communicating

Example

let jobs = Chan<Int>(5)  // buffered channel
let done = Chan<Bool>()  // unbuffered channel

dispatch {
    for ;; {
        if let j = <-jobs {
            print("received job \(j)")
        } else {
            print("received all jobs")
            done <- true
            return
        }
    }
}

for var j = 1; j <= 3; j++ {
    jobs <- j
    print("sent job \(j)")
}
jobs.close()
print("sent all jobs")

<-done

Iterate

A channel can also be iterated through.

while let j = <-jobs {
    print("received job \(j)")
}
print("received all jobs")

Select

The _select keyword is a multiway communications multiplexer that works on multiple channels. _select, _case, and _default start with underscores so that they do not conflict with the select, case, and default syscall and keywords. When a _select encounters multiple channels with data, the chosen _case is selected at random

let jobs1 = Chan<Int>()
let jobs2 = Chan<Int>()

dispatch {
    for ;; {
        _select {
            _case(jobs1){ j in
                print("received 1: \(j)")
            }
            _case(jobs2){ j in
                print("received 2: \(j)")
            }
        }
    }
}

for var j = 1; ; j++ {
    jobs1 <- (j * 1000)
    jobs2 <- (j * 2000)
    NSThread.sleepForTimeInterval(1)
}

Select with Default

A _select can contain a single _default for non-blocking operations.

_select {
    _case(jobs1){ j in
        print("received 1: \(j)")
    }
    _case(jobs2){ j in
        print("received 2: \(j)")
    }
    _default {
        print("channels not ready")
    }
}

Mutex, Cond, Once, WaitGroup

Incredibly useful sync APIs.

Mutex

let m = Mutex()
m.lock()           
m.unlock()         
m.lock {
    // this block is locked
}

Cond

let c = Cond(Mutex())
c.wait()                // wait for signal.
c.wait(0.25)            // wait for signal or 250ms to pass.
c.signal()              // signal to one wait.
c.broadcast()           // signal to all waits.

Once

func f(){
    print("hey there")
}

let o = Once()
o.doit(f)               // runs once
o.doit(f)               // noop: cannot run twice

WaitGroup

let dosomething : (NSTimeInterval, WaitGroup)->() = { (delay, wg) in
    NSThread.sleepForTimeInterval(delay)
    print("Function in background, duration: \(delay)")
    wg.done()
}
let wg = WaitGroup()
wg.add(1)
dispatch { dosomething(0.40, wg) }
wg.add(1)
dispatch { dosomething(0.30, wg) }
wg.add(1)
dispatch { dosomething(0.15, wg) }
wg.add(1)
dispatch { dosomething(0.60, wg) }
wg.wait()
print("done")

##Installation (iOS and OS X)

Carthage

Add the following to your Cartfile:

github "tidwall/Safe"

Then run carthage update.

Follow the current instructions in Carthage's README for up to date installation instructions.

The import Safe directive is required in order to access Safe features.

CocoaPods

Add the following to your Podfile:

use_frameworks!
pod 'Safe'

Then run pod install with CocoaPods 0.36 or newer.

The import Safe directive is required in order to access Safe features.

SPM

Add the following to your Package.swift

    dependencies: [
        ...
        .Package(url: "https://github.com/tidwall/Safe", majorVersion: 1, minor: 2)
    ]

Then run swift build.

The import Safe directive is required in order to access Safe features.

Manually

Copy the Source/*.swift file into your project.

There is no need for import Safe when manually installing.

Contact

Josh Baker @tidwall

License

The Safe source code is available under the MIT License.

Comments
  • error using SPM - fix: move the file(s) inside a module

    error using SPM - fix: move the file(s) inside a module

    Fetching https://github.com/tidwall/Safe Cloning https://github.com/tidwall/Safe Resolving https://github.com/tidwall/Safe at 1.2.1 error: the package has an unsupported layout, unexpected source file(s) found: /Users/johndpope/Documents/tensorFlowWorkspace/tensorflow/tensorflow/swift/.build/checkouts/Safe-5061242610371348105/Tests/atomic-test.swift, /Users/johndpope/Documents/tensorFlowWorkspace/tensorflow/tensorflow/swift/.build/checkouts/Safe-5061242610371348105/Tests/bridge.m, /Users/johndpope/Documents/tensorFlowWorkspace/tensorflow/tensorflow/swift/.build/checkouts/Safe-5061242610371348105/Tests/chan-test.swift, /Users/johndpope/Documents/tensorFlowWorkspace/tensorflow/tensorflow/swift/.build/checkouts/Safe-5061242610371348105/Tests/dispatch-test.swift, /Users/johndpope/Documents/tensorFlowWorkspace/tensorflow/tensorflow/swift/.build/checkouts/Safe-5061242610371348105/Tests/sync-test.swift, /Users/johndpope/Documents/tensorFlowWorkspace/tensorflow/tensorflow/swift/.build/checkouts/Safe-5061242610371348105/Tests/test.swift fix: move the file(s) inside a module

    I included files - but am getting these errors - perhaps this PR will fix? https://github.com/tidwall/Safe/pull/15

    opened by johndpope 1
  • now swift3 builds and unit test runs, not know if it have some bugs h…

    now swift3 builds and unit test runs, not know if it have some bugs h…

    Now it builds with swift3 and unit test is working for OSX(didn't tested on linux yet).

    The pull request I've pushed is only swift3 adapted.

    Have changed a lot in atomic file, BooleanType protocol is removed so I used some brutal ways to get it fixed(value as! Bool) with all && and || functionalities, this might be a big problem here,but I'didn't came up with a good solution here. Also in displatch.swift file, I've get it running by copied part of Strand(pthread wrapper) codes into the file, otherwise I cannot get it running.

    I don't have much experience working on C bridge with swift before, so it would be real appreciated if anyone who have more experience on this part can take it look, the way I'm get it running I think might be somewhat real dangerous.

    Hope it helps :)

    opened by eminarcissus 1
  • Removed offending lines

    Removed offending lines

    I think these lines have been depreciated

    sources: https://guides.cocoapods.org/syntax/podspec.html#platform https://guides.cocoapods.org/syntax/podspec.html#deployment_target

    opened by lufthansa747 1
  • pod install errors

    pod install errors

    in my podfile i have

    use_frameworks! pod 'Safe', :git => 'https://github.com/tidwall/Safe.git'

    and when i run pod install i get

    Analyzing dependencies Pre-downloading: Safe from https://github.com/tidwall/Safe.git [!] Unable to find a specification for 'Safe'.

    [!] Unable to load a podspec from Safe.podspec, skipping:

    Pod::DSLError

    just using "pod 'Safe'" in the pod file doesn't work either

    opened by lufthansa747 1
  • Error handling

    Error handling

    First of all great work with this library!

    This is not really an issue, but more of a design problem. I typically use channels to coordinate the asynchronous corner of an app.

    My question is how do I design an async response (either succes or error) and put it on a channel? I came up with something like

    // renamed `dispatch` to `go`
    go {  
           let chans = fetchLogin(user)
           // fetch login calls my api and returns a tuple: fetchlogin(user: User) -> (Chan<Error>, Chan<User>)
           _select {
              _case(chans.0){ err in /*do stuff with the error*/}
              _case(chans.1){ resp in /*do stuff with the success response*/}
          }
    }
    

    I have no idea if this is an elegant solution, I'm coming from dynamic languages where I could just put both an error and a valid response on one channel, then I would determine if it was an error or valid response when taking the value from the channel. Here channels are typed, I can't put both on the same channel. I just put them on different channels.

    The current 'best practice' with Swift is designing an Enum:

    Enum Response<T> {
       case Success(T)
       case Failure(Error)
    }
    

    I tried putting such an enum on a Channel, but Swift's type system doesn't accept it.

    Any ideas? Maybe I can make it into a recipe and put it in the docs of this repo.

    question 
    opened by IwanKaramazow 1
  • Swift 4

    Swift 4

    I think I've brought things up to date for Swift 4, from the Swift 3 patch ot-waku did, though I can't be sure I haven't accidentally created a memory leak in dispatch or something. I successfully ran a simple test, though, so it SEEMS to work.

    opened by Erhannis 0
  • Update README

    Update README

    • Removes Swift 2.0 badge
    • Adds Swift 2.2 badge
    • Adds Platform badge
    • New badges use resolution independent SVGs from img.shields.io
    • Add section on adding to Package.swift
    opened by ssoper 0
  • Reduce anyGenerator deprecation warning.

    Reduce anyGenerator deprecation warning.

    Swift 2.2+ replaced anyGenerator with AnyGenerator and prints a deprecation warning to the console during the build process.

    Source/chan.swift:119:16: warning: 'anyGenerator' is deprecated: renamed to 'AnyGenerator'
    Source/chan.swift:119:16: note: use 'AnyGenerator' instead
    

    Using AnyGenerator breaks 2.1 and below. I currently do not know of a backwards compatible way to suppress this warning.

    opened by tidwall 0
Owner
Josh Baker
Josh Baker
The projects and materials that accompany the Modern Concurrency in Swift book

Modern Concurrency in Swift: Materials This repo contains all the downloadable materials and projects associated with the Modern Concurrency in Swift

raywenderlich 137 Dec 16, 2022
Venice - Coroutines, structured concurrency and CSP for Swift on macOS and Linux.

Venice provides structured concurrency and CSP for Swift. Features Coroutines Coroutine cancelation Coroutine groups Channels Receive-only chan

Zewo 1.5k Dec 22, 2022
Slack message generator and API client, written in Swift with Result Builders and Concurrency

Slack Message Client This package provides a Swift object model for a Slack Block Kit message, as well as a Result Builder convenience interface for e

Mike Lewis 2 Jul 30, 2022
A complete set of primitives for concurrency and reactive programming on Swift

A complete set of primitives for concurrency and reactive programming on Swift 1.4.0 is the latest and greatest, but only for Swift 4.2 and 5.0 use 1.

AsyncNinja 156 Aug 31, 2022
A Swift DSL that allows concise and effective concurrency manipulation

NOTE Brisk is being mothballed due to general incompatibilities with modern version of Swift. I recommend checking out ReactiveSwift, which solves man

Jason Fieldman 25 May 24, 2019
⚡️ Fast async task based Swift framework with focus on type safety, concurrency and multi threading

Our apps constantly do work. The faster you react to user input and produce an output, the more likely is that the user will continue to use your appl

Said Sikira 814 Oct 30, 2022
Tools for using Swift Concurrency on macOS 10.15 Catalina, iOS 13, tvOS 13, and watchOS 6.

ConcurrencyCompatibility Tools for using Swift Concurrency on macOS 10.15 Catalina, iOS 13, tvOS 13, and watchOS 6. Xcode 13.2 adds backwards deployme

Zachary Waldowski 9 Jan 3, 2023
A declarative state management and dependency injection library for SwiftUI x Concurrency

A declarative state management and dependency injection library for SwiftUI x Concurrency

Ryo Aoyama 199 Jan 1, 2023
Swift concurrency collection support

AsyncCollections Functions for running async processes on Swift Collections ForEach Run an async function on every element of a Sequence. await array.

Adam Fowler 11 Jul 11, 2022
An introduction to using Swift's new concurrency features in SwiftUI

SwiftUI Concurrency Essentials An introduction to using Swift's new concurrency features in SwiftUI Discuss with me · Report Bug · Request Feature Art

Peter Friese 80 Dec 14, 2022
Type-safe networking with Swift Concurrency

AsyncRequest AsyncRequest is a type-safe framework for building a suite of requests to communicate with an API, built on top of Swift Concurrency. Ins

Light Year Software, LLC 1 Feb 9, 2022
Functional Concurrency Primitives

Concurrent Concurrent is a collection of functional concurrency primitives inspired by Concurrent ML and Concurrent Haskell. Traditional approaches to

TypeLift 206 Dec 24, 2022
AsyncOperators brings some features of RxSwift/Combine to Structured Concurrency

AsyncOperators brings some features of RxSwift/Combine to Structured Concurrency, such as combineLatest and distinctUntilChanged.

Ben Pious 3 Jan 18, 2022
Ten Elephants is the modern cooking app for iPhone.

Ten Elephants Ваш персональный гастро-ассистент на iPhone. Поиск по названию/ингредиентам Поиск блюд по ингредиентам Что популярно сегодня Случайное б

null 5 Dec 22, 2021
Async and concurrent versions of Swift’s forEach, map, flatMap, and compactMap APIs.

CollectionConcurrencyKit Welcome to CollectionConcurrencyKit, a lightweight Swift package that adds asynchronous and concurrent versions of the standa

John Sundell 684 Jan 9, 2023
Automatically generate GraphQL queries and decode results into Swift objects, and also interact with arbitrary GitHub API endpoints

GitHub API and GraphQL Client This package provides a generic GitHub API client (GithubApiClient) as well as Codable-like GitHub GraphQL querying and

Mike Lewis 4 Aug 6, 2022
Make your logic flow and data flow clean and human readable

Flow What's Flow Flow is an utility/ design pattern that help developers to write simple and readable code. There are two main concerns: Flow of opera

null 18 Jun 17, 2022
Extensions and additions to AsyncSequence, AsyncStream and AsyncThrowingStream.

Asynchone Extensions and additions to AsyncSequence, AsyncStream and AsyncThrowingStream. Requirements iOS 15.0+ macOS 12.0+ Installation Swift Packag

Red Davis 101 Jan 6, 2023
straightforward networking and error handling with async-await and URLSession

AsyncAwaitNetworkingPlayground How To Run Just clone the project, open it and run. Some notes about AsyncAwaitNetworkingPlayground It's a straightforw

Fırat Yenidünya 17 Dec 11, 2022