Git Product home page Git Product logo

swiftsafe's Introduction

SwiftSafe

Thread synchronization made easy.

โ“ Why?

Performance-sensitive classes need internal state synchronization, so that external accessors don't break the internal invariants and cause race conditions. Using GCD (Grand Central Dispatch) directly can confuse newcomers, because the API doesn't necessarily reflect the actual reason why it's being used. That's why wrapping it in a straighforward Swifty API can introduce a bit more clarity to your code. See examples below.

โŒš Concurrency modes supported

  • EREW - Exclusive Read, Exclusive Write: The most common synchronization method, where only one thread can read or write your protected resource at one time. One big disadvantage is that it's prone to deadlocks.
  • CREW - Concurrent Read, Exclusive Write: Less common, but IMO more powerful method, where multiple threads can read, but only one thread can write at one time. Reading and writing is automatically made exclusive, i.e. all reads enqueued before a write are executed first, then the single write is executed, then more reads can be executed (those enqueued after the write).

:octocat: Installation

Get SwiftSafe on CocoaPods, just add pod 'SwiftSafe' to your Podfile.

๐ŸŽ“ Usage

Let's say you're writing a thread-safe NSData cache. You'd like it to use CREW access to maximize performance.

class MyCache {
	private let storage: NSMutableDictionary = NSMutableDictionary()
	public func hit(key: String) -> NSData? {
		let found = self.storage[key]
		if let found = found {
			print("Hit for key \(key) -> \(found)")
		} else {
			print("Miss for key \(key)")
		}
		return found
	}
	public func update(key: String, value: NSData) {
		print("Updating \(key) -> \(value)")
		self.storage[key] = value
	}
}

This is the first implementation. It works, but when you start calling it from multiple threads at the same time, you'll encounter inconsistencies and race conditions - meaning you'll be getting different results with the same sequence of actions. In more complicated cases, you might even cause a runtime crash.

The way you fix it is obviously by protecting the internal storage (note: NSDictionary is not thread-safe). Again, to be most efficient, we want to allow any number of threads reading from the cache, but only one to update it (and ensure that nobody is reading from it at that time). You can achieve these guarantees with GCD, which is what SwiftSafe does. What this API brings to the table, however, is the simple and obvious naming.

Let's see how we can make our cache thread-safe in a couple lines of code.

import SwiftSafe

class MyCache {
	private let storage: NSMutableDictionary = NSMutableDictionary()
	private let safe: Safe = CREW()
	public func hit(key: String) -> NSData? {
		var found: NSData?
		safe.read {
			found = self.storage[key]
			if let found = found {
				print("Hit for key \(key) -> \(found)")
			} else {
				print("Miss for key \(key)")
			}
		}
		return found
	}
	public func update(key: String, value: NSData) {
		safe.write {
			print("Updating \(key) -> \(value)")
			self.storage[key] = value
		}
	}
}

That's it! Just import the library, create a Safe object which follows the concurrency mode you're trying to achieve (CREW in this case) and wrap your accesses to the shared resource in read and write calls. Note that read closures always block the caller thread, whereas write don't. If you ever have a call which both updates your resource and reads from it, make sure to split that functionality into the writing and reading part. This will make it much easier to reason about and parallelize.

๐Ÿ‘‰ Bottom line

Even though it might sound unnecessary to some, understandable and correct methods of synchronization will save you days of debugging and many headaches. :)

๐Ÿ’™ Code of Conduct

Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.

โœŒ๏ธ License

MIT

๐Ÿ‘ฝ Author

Honza Dvorsky - http://honzadvorsky.com, @czechboy0

swiftsafe's People

Contributors

czechboy0 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.