Skip to content

Commit

Permalink
Merge pull request #6 from ktatroe/thread_safe_container
Browse files Browse the repository at this point in the history
Change Container to be thread-safe
  • Loading branch information
ktatroe committed Nov 21, 2016
2 parents 4dc8cb4 + f238f26 commit 490797f
Showing 1 changed file with 23 additions and 1 deletion.
24 changes: 23 additions & 1 deletion Horatio/Container/Container.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ public class Container {

private var services = [ContainerItemKey: ContainerItemType]()

// we need a recursive lock, because sometimes we do a resolve() inside a resolve()
private let servicesLock = NSRecursiveLock()

public func register<T>(serviceType: T.Type, name: String? = nil, factory: Resolvable -> T) -> ContainerEntry<T> {
return registerFactory(serviceType, factory: factory, name: name)
}
Expand All @@ -48,6 +51,13 @@ public class Container {
let key = ContainerItemKey(factoryType: factory.dynamicType, name: name)
let entry = ContainerEntry(serviceType: serviceType, factory: factory)

// ensure no other access while writing
servicesLock.lock()

defer {
servicesLock.unlock()
}

services[key] = entry

return entry
Expand All @@ -73,8 +83,20 @@ extension Container : Resolvable {
internal func resolveFactory<T, Factory>(name: String?, invoker: Factory -> T) -> T? {
let key = ContainerItemKey(factoryType: Factory.self, name: name)

if let entry = services[key] as? ContainerEntry<T> {
var lockedEntry: ContainerItemType? = nil

// read from data structure in a thread-safe manner
servicesLock.lock()

defer {
servicesLock.unlock()
}

lockedEntry = services[key]

if let entry = lockedEntry as? ContainerEntry<T> {
if entry.instance == nil {
// this is doing a write to a shared object, and also must happen inside the lock
entry.instance = resolveEntry(entry, key: key, invoker: invoker) as Any
}

Expand Down

0 comments on commit 490797f

Please sign in to comment.