Modern Concurrency and Synchronization for Swift.
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
Generator suppress swift 2.2 warning Jan 11, 2016
Safe.xcodeproj testing Jul 2, 2015
Source updated syntax Jul 8, 2016
Tests suppress swift 2.2 warning Jan 11, 2016
.gitignore Now builds on Ubuntu Jan 7, 2016
.swift-version Now builds on Ubuntu Jan 7, 2016
Dockerfile Now builds on Ubuntu Jan 7, 2016
LICENSE license Jun 30, 2015
Package.swift Now builds on Ubuntu Jan 7, 2016
README.md Merge branch 'bump-readme' of https://github.com/ssoper/Safe into sso… Jul 8, 2016
Safe.podspec bump 1.2.1 Jul 8, 2016

README.md


Swift 2.2 Platforms OS X | iOS | Linux

##Features

  • Simple Atomic<T> class for numbers and strings.
  • Uncomplicated dispatch keyword for firing off background routines.
  • Awesome Chan<T> 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<Int>.
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<T> class provides a clean and simple model for concurrently sharing objects. Chan<T> 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.