hmlongco / Resolver

Swift Ultralight Dependency Injection / Service Locator framework
MIT License
2.15k stars 190 forks source link

cachedServices is not thread safe #12

Closed mycroftcanner closed 4 years ago

mycroftcanner commented 5 years ago

Any chance you could make the application cache thread safe?

In general I only let the strict necessary on the main thread and I use Texture so everything runs in the background except for strict UIKit and some SwiftUI stuff

Maybe implementing a lock on the cachedServices would help:

            cachedServices[registration.cacheKey]
hmlongco commented 5 years ago

You mean like using mutex to do thread locking?

    public final func resolve<Service>(resolver: Resolver, registration: ResolverRegistration<Service>, args: Any?) -> Service? {
        pthread_mutex_lock(&mutex)
        defer { pthread_mutex_unlock(&mutex) }
        if let service = cachedServices[registration.cacheKey] as? Service {
            return service
        }
        let service = registration.resolve(resolver: resolver, args: args)
        if let service = service{
            cachedServices[registration.cacheKey] = service
        }
        return service
    }
hmlongco commented 5 years ago

I might mention that if you're using Resolver in a project it might be worth your while to spend the 15-20 minutes it would take to read the documentation... ;)

Further, Resolver: Is tested in production code. Is thread safe (assuming your objects are thread safe). Has a complete set of unit tests. Is well-documented.

mycroftcanner commented 5 years ago

Sorry about that... I am so used to project not using mutex or barriers...

I just assumed or was tired as it was right in front of my eyes.

mycroftcanner commented 5 years ago

I had a bad access on cachedServices[registration.cacheKey].

I didn't investigate and just assumed. A quick fix was to call the registration early.

Now I can't reproduce the problem. What do you think could have caused a bad access on cachedServices?

mycroftcanner commented 5 years ago

Finally managed to reproduce the issue:

image image

@hmlongco any ideas what would be the cause?

mycroftcanner commented 5 years ago

The factory instance is injected in my SceneDelegate:

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    @Injected private var auth: Auth
    @Injected private var factory: WindowFactory

    [...]

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        if let windowScene = scene as? UIWindowScene {
            window = factory.makeWindow(windowScene: windowScene)
        }
    }

then my environment objects are injected inside the Factory class:

    // Used a EnvironmentObjects in SwiftUI view hierarchies
    @Injected private var auth: Auth
    @Injected private var settings: SettingsStore

Is there a race condition or am I doing something wrong?

mycroftcanner commented 4 years ago

@hmlongco ??

hmlongco commented 4 years ago

Download and try the develop branch. I added locking around the registerAllServices call. Also I'm not sure what injection code you're using as that's been updated as well.

mycroftcanner commented 4 years ago

thanks I'll try

mycroftcanner commented 4 years ago

I can't find the @Injected property wrapper in this repo I am using the code in your blog post.

We couldn’t find any code matching 'propertyWrapper' in hmlongco/Resolver

hmlongco commented 4 years ago

@Injected (and @LazyInjected) is in the develop branch at the moment.

mycroftcanner commented 4 years ago

I am still encountering random crashes at init ... have you tried using a dispatch queue barrier instead of a pthread mutex?

mycroftcanner commented 4 years ago
image
hmlongco commented 4 years ago

Checkout the develop branch. I think it helps if the mutexes are initialized... :(

On Dec 16, 2019, at 3:36 PM, Mycroft Canner notifications@github.com wrote:

https://user-images.githubusercontent.com/55385694/70944976-775ac300-2054-11ea-88ef-3a78c10b50b5.png — You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub https://github.com/hmlongco/Resolver/issues/12?email_source=notifications&email_token=AAFNFIZSPMM4WE6XSNZ4X2TQY7YFFA5CNFSM4JDD23V2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEHAFXKY#issuecomment-566254507, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFNFI3AONKB4OJBASW2MJTQY7YFFANCNFSM4JDD23VQ.