Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple Threads access #30

Closed
Parkyprg opened this issue Aug 23, 2016 · 62 comments
Closed

Multiple Threads access #30

Parkyprg opened this issue Aug 23, 2016 · 62 comments
Assignees

Comments

@Parkyprg
Copy link

In one of my applications I am accessing/updating db objects from multiple threads and for some reason it simply freeze.
I am trying to narrow it down, but being multi-threaded, seems to be difficult.

Are there any special steps to make, in order to work with the objects from multiple threads?

@editfmah
Copy link
Owner

Nope, nothing to do at all.

In fact in the unit tests there are lots of examples of up to 50 threads all reading/writing/deleting at the same time.

There is a critical section around a write op to a database, but these will not block reads. And transactions are partitioned by thread as well, so unless there is a huge op within a large transaction, you should not see, much in the way of blocking.

Any additional information you could provide would be helpful. Is there anything special about what you are persisting? e.g. large BLOB objects, or very wide objects?

@Parkyprg
Copy link
Author

Parkyprg commented Sep 6, 2016

It seems I am not able to find a reason, but I suspect is somehow related to the framework (at least maybe to the way I am using it).

As a background - I am sending a few server requests from different threads to fetch some data (using AFNetworking). When the results come, I insert/update them in the database with SharkORM.

The problem is that the app simply freeze (like entering in an endless loop) - but not always at the same step and what is most frustrating - it happens a few times per each 100 runs (or so).
If a pause it from xCode, I see different threads, stuck at some SharkORM methods. For example now I have the following:
Thread 1 - freezed at SRKQuery whereWithFormat - when it sets "self.whereClause = format;". In the steps I see this object has been initialized from a removeAll method of SRKResultSet.
Thread 4 - freezed at SRLObject setPropertyBoolIMP - when it sets a boolean value on a field.

I will try to note down where it happens each time but unfortunately I don't know how I can reproduce it properly.

Any thoughts are highly appreciated.

PS - it's not like a temporary block - it freezes forever, no matter what I do. I am storing only simple values - like NSNumber, NSString, BOOL, double and a few relations between tables.

Is it possible that I could enter in a deadlock or something (like referentiating A from B and also B from A)?

@Parkyprg
Copy link
Author

Parkyprg commented Sep 7, 2016

I don't think there is a deadlock - because in that case it would freeze all the time at the same place/moment.

@editfmah
Copy link
Owner

editfmah commented Sep 7, 2016

Hi Sorry for not getting back to you yesterday, I would agree. The deadlocks always show themselves waiting for a semaphore, and we only have the one critical section as far as I can remember around write operations.

You have done quite a lot of investigation already. And we also use AFNetworking in the same kind of way. We modified AFNetworking to always use background threads and not all crashing in on the main thread, but that would be the only difference.

Are you seeing any errors on the delegate? Locked SQL file, index corruption, anything like that?

@editfmah
Copy link
Owner

editfmah commented Sep 7, 2016

Also, i'd never expect a freeze on your example of thread 4. I'd be looking at what priority those dispatch items were, and if they got suspended by GCD for higher priority blocks? But i'm really scraping the barrel for ideas there.

@Parkyprg
Copy link
Author

Parkyprg commented Sep 7, 2016

Thank you for your reply.
I managed to get it reproduced all the time now. This should make things easier (in theory :)).
I have 2 relevant threads, always the same ones:
Thread 1: Stuck at [SRKQuery setOrderBy]
Thread 5: Stuck at setting a BOOL property. Runs in a concurrent queue.

I am attaching 2 images with what I think it might be relevant.

thread-1
thread-5

@editfmah
Copy link
Owner

editfmah commented Sep 7, 2016

Thanks for the info, it's very weird. As the "setPropertyIMP", is only on a single object, and shares nothing with other objects or the ORM. There is quite literally no reason why it would ever block there.

What created the block and dispatched it? Was it an AFNetworking response block? Could you try dispatching one of those blocks on a different queue:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// loop through doing your update here.
});

I appreciate that this is normally a nightmare to try and break your app apart to make a bit of it async. But might I suggest using an NSLock to hold a semaphore until the dispatched block has completed.

I'm just interested to see if you break out of this dispatch queue, whether or not it starts to work.

It might give us at least a direction to head in.

P.S. does this happen on an entirely repeatable basis, or is it intermittent?

@editfmah
Copy link
Owner

editfmah commented Sep 9, 2016

Hy @Parkyprg,

Is there anything specific you would like me to look at, or a scenario I could setup that you think would be the best possible chance to replicate your issue? I have a couple of free hours today that can be dedicated to trying to work out this issue.

Thanks
Adrian

@Parkyprg
Copy link
Author

Hi Adrian,

I managed to reproduce the problem in a separate project. Can you tell me an email address where I can send you the source files?

Thank you,
Cristi

@sharkorm
Copy link
Collaborator

Hi,

devs@db-access.org.

Looking forward to fixing it!

Sent from my iPhone

On 12 Sep 2016, at 05:37, Parkyprg notifications@github.com wrote:

Hi Adrian,

I managed to reproduce the problem in a separate project. Can you tell me an email address where I can send you the source files?

Thank you,
Cristi


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.

@Parkyprg
Copy link
Author

Email sent. Forgot to mention it here :)

@Parkyprg
Copy link
Author

I was wondering if you were able to reproduce the problem with the test project that I sent.

@editfmah
Copy link
Owner

Just looking now, but so far unable to reproduce. Does this happen on devices or the simulator, or both?

On 14 Sep 2016, at 09:46, Parkyprg notifications@github.com wrote:

I was wondering if you were able to reproduce the problem with the test project that I sent.


You are receiving this because you were assigned.
Reply to this email directly, view it on GitHub #30 (comment), or mute the thread https://github.com/notifications/unsubscribe-auth/ADUZ3u34rm9Ezue5Laoy172CjD0cFcNbks5qp7SAgaJpZM4JqlVI.

@Parkyprg
Copy link
Author

Mostly on device.
Try to add many contacts, so it can spend more time on that particular job.

@editfmah
Copy link
Owner

Hi, i'm just trying to get it on a phone, but in the simulator we added 1000 contacts to really stretch it.

@Parkyprg
Copy link
Author

On simulator I believe the time spent processing the contacts is too short.
Try on a device to add some random contacts with the second project that I sent you.

@editfmah
Copy link
Owner

Okay, I will try that when our testing team get here. I'd prefer not to create loads of addresses on my personal phone. As actually, the app just crashes on iOS 10, as it tries to access the contacts before it asks for permissions. I'm just going to add it in manually now.

UPDATE: The permission for Contacts is not present in iOS 10 (it crashes before it adds the entitlement I think), so I can't manually add it. I'll wait for an iOS 9 device. Will get back to you soon.

@editfmah
Copy link
Owner

Right, i've managed to re-create the hang (it took a lot of trying), however, in this particular case it was not utilising shark at all, but had been blocked by two threads both creating a runloop for the contacts API at the same time. I will continue looking to see if I can't pin it down further.

screen shot 2016-09-15 at 09 24 39

@editfmah
Copy link
Owner

editfmah commented Sep 15, 2016

Also, what device/iOS version are you using? I'll try and match that this end if I can for a better and more accurate test. I'm currently using an iPhone 6 running iOS 9. 1000 contacts.

@Parkyprg
Copy link
Author

I am using the same device - 6 with iOS 9.3.5

@editfmah
Copy link
Owner

Hi, I'm going to look at this again today. Is there any further information/investigation for this issue?

@Parkyprg
Copy link
Author

Thank you for looking into this.
However, there are no new information. It still freezes.

I am not 100% sure this is caused by the framework but every time it happens - 2 threads are locked on SharkORM processes.

@Parkyprg
Copy link
Author

Hi,

Were you able to find anything? At least did you managed to reproduce it on a test device?

@editfmah
Copy link
Owner

I've only been testing for about 1/2 an hour, but so far it has not locked up once. When I did manage to get it to freeze last time it happened to not be doing anything in Shark. Another time, it froze whilst on the line.

idx++;

Which, really just has to be symptomatic of the co-ordinating thread locking. Knowledge of how iOS/OSx manages it's thread hierarchy is not known to me, but I would have thought there will be a base level runloop (thread) that controls all the others, but I would need to ask someone on SO who may be more knowledgeable.

Shark, as a general rule does nothing in any background threads, it merely executes it's code in-line with the developers intentions. We do use performSelectorInBackground: if you're performing async queries, but these are the specific differences.

So, although unable so far to identify the culprit, i'm struggling to find any reason to believe it is the ORM. Although I do maintain a completely open mind.

I will do some more testing over the next hour or so. Possibly on some older / single core devices.

Thanks
Adrian

@lbwxly
Copy link

lbwxly commented Oct 18, 2016

Any update for this issue? i also get freeze sometimes at following line
SRKObject class

  • (id)init {
    ...
    if ([[r.sourceClass description] isEqualToString:entityName]) {
    ...
    }

this is called from main thread

@editfmah
Copy link
Owner

Hi,

I looked again recently at this, but in the other instance, the code would stop in the middle of nowhere and in places that could not possibly ever pause. Yours however might be different.

So, a few questions. Does your hang ever continue, or is a transient pause?

Are there other DB operations happening in the background? (they would have to be huge to cause any sort of delay).

Is this call normally within any kind of transaction?

But I will look at that method now to see if there is anything I can spot.

@lbwxly
Copy link

lbwxly commented Oct 18, 2016

it pause at this line every time, we can see the thread is wait for some thing from the stack trace. it is not a transient pause. i think there is not any background access, since it occur when our app just launch

@lbwxly
Copy link

lbwxly commented Oct 19, 2016

  • thread Fixed for multiple joins & joins based on A->B->C. Fixed compiler warnings. #1: tid = 0x382170, 0x000000010a1d2db6 libsystem_kernel.dylib__psynch_cvwait + 10, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP frame #0: 0x000000010a1d2db6 libsystem_kernel.dylibpsynch_cvwait + 10
    frame Fixed for multiple joins & joins based on A->B->C. Fixed compiler warnings. #1: 0x000000010a198728 libsystem_pthread.dylib_pthread_cond_wait + 767 frame #2: 0x0000000104e48eed libobjc.A.dylibmonitor_tt::wait() + 19
    frame Added new print output format #3: 0x0000000104e48b58 libobjc.A.dylib_class_initialize + 512 frame #4: 0x0000000104e4ecc5 libobjc.A.dyliblookUpImpOrForward + 176
    frame Incremented version in Header to 2.0.3 & Podspec #5: 0x0000000104e5d8bb libobjc.A.dylibobjc_msgSend + 187 frame #6: 0x0000000104e558b5 libobjc.A.dylibobjc_getProperty_non_gc(objc_object
    , objc_selector
    , long, bool) + 68
    frame Inheritance Support? #7: 0x00000001035bcf18 EAMInventory-[SRKObject init](self=0x00007feeb1496870, _cmd="init") + 2792 at SRKObject.m:1705 frame #8: 0x00000001036ef081 EAMInventorySerializableDataEntity.init() -> SerializableDataEntity + 49 at SerializableDataEntity.swift:0
    frame support for Carthage #9: 0x00000001037c1da8 EAMInventorySyncEntity.init() -> SyncEntity + 40 at SyncEntity.swift:0 frame #10: 0x00000001037c28d7 EAMInventoryWritableSyncEntity.init() -> WritableSyncEntity + 55 at SyncEntity.swift:0
    frame Subclass support #11: 0x0000000103a5353c EAMInventoryDepartment.init() -> Department + 188 at Department.swift:0 frame #12: 0x0000000103a5357c EAMInventoryDepartment.__allocating_init() -> Department + 44 at Department.swift:0

    thread Updates for Tests #2: tid = 0x3822f1, 0x000000010a1d3ee2 libsystem_kernel.dylibkevent64 + 10, queue = 'com.apple.libdispatch-manager' frame #0: 0x000000010a1d3ee2 libsystem_kernel.dylibkevent64 + 10
    frame Fixed for multiple joins & joins based on A->B->C. Fixed compiler warnings. #1: 0x0000000109e32408 libdispatch.dylib_dispatch_mgr_invoke + 260 frame #2: 0x0000000109e321a2 libdispatch.dylib_dispatch_mgr_thread + 54

    thread Added new print output format #3: tid = 0x3822f4, 0x000000010a1cd06e libsystem_kernel.dylibsyscall_thread_switch + 10, queue = 'com.demo.eam.databaseAccess' frame #0: 0x000000010a1cd06e libsystem_kernel.dylibsyscall_thread_switch + 10
    frame Fixed for multiple joins & joins based on A->B->C. Fixed compiler warnings. #1: 0x000000010a1ad1cd libsystem_platform.dylib_os_lock_handoff_lock_slow + 111 frame #2: 0x0000000104e558ad libobjc.A.dylibobjc_getProperty_non_gc(objc_object_, objc_selector_, long, bool) + 60
    frame Added new print output format #3: 0x00000001036b93e6 EAMInventory+[SharkORM addEntityRelationship:inDatabase:](self=SharkORM, _cmd="addEntityRelationship:inDatabase:", r=0x00007feeb1427140, dbName=@"EAM") + 262 at SharkORM.m:999 frame #4: 0x00000001035b6821 EAMInventory+[SRKObject setupClass](self=EAMInventory.ProjectAttribute, _cmd="setupClass") + 6129 at SRKObject.m:1598
    frame Incremented version in Header to 2.0.3 & Podspec #5: 0x00000001035bc110 EAMInventory+[SRKObject initialize](self=EAMInventory.ProjectAttribute, _cmd="initialize") + 32 at SRKObject.m:1636 frame #6: 0x0000000104e48bff libobjc.A.dylib_class_initialize + 679
    frame Inheritance Support? #7: 0x0000000104e4ecc5 libobjc.A.dyliblookUpImpOrForward + 176 frame #8: 0x0000000104e5d8bb libobjc.A.dylibobjc_msgSend + 187
    frame support for Carthage #9: 0x000000010391ea8c EAMInventorytype metadata accessor for ProjectAttribute + 44 at ProjectAttribute.swift:0 frame #10: 0x000000010392b99b EAMInventoryProject.init() -> Project + 443 at Project.swift:30
    frame Subclass support #11: 0x000000010392bac1 EAMInventory@objc Project.init() -> Project + 17 at Project.swift:0 frame #12: 0x00000001036c7108 EAMInventory__35-[SharkORM fetchEntitySetForQuery:]_block_invoke(.block_descriptor=, statement=0x00007feeb17d3900, resultsSet=@"0 elements") + 616 at SharkORM.m:2291
    frame Share the iOS framework scheme to support Carthage. #13: 0x00000001036c60be EAMInventory-[SharkORM performQuery:rowBlock:](self=0x00007feeb2a019b0, _cmd="performQuery:rowBlock:", query=0x00007feeb2a01b70, rowBlock=0x00007000000934a0) + 12110 at SharkORM.m:2184 frame #14: 0x00000001036c6e56 EAMInventory-[SharkORM fetchEntitySetForQuery:](self=0x00007feeb2a019b0, _cmd="fetchEntitySetForQuery:", query=0x00007feeb2a01b70) + 198 at SharkORM.m:2276
    frame Last version #15: 0x00000001035abb74 EAMInventory-[SRKQuery fetch](self=0x00007feeb2a01b70, _cmd="fetch") + 692 at SRKQuery.m:436 frame #16: 0x0000000103a5e9d9 EAMInventoryProjectDal.(self=0x00007feeb17a5440, observer=(action = 0x00000001046afc30 ReactiveCocoapartial apply forwarder for ReactiveCocoa.SignalProducer.(startWithSignal ((ReactiveCocoa.Signal<A, B>, ReactiveCocoa.Disposable) -> ()) -> ()).(closure #2) at SignalProducer.swift)) -> SignalProducer<Project?, EAMError>).(closure #1).(closure #1) + 921 at ProjectDal.swift:190 frame #17: 0x0000000103906eee EAMInventoryBaseDal.(self=0x00007feeb17a5440, block=0x0000000103a5af60 EAMInventorypartial apply forwarder for EAMInventory.ProjectDal.(getCurrentProject () -> ReactiveCocoa.SignalProducer<Swift.Optional<EAMInventory.Project>, EAMInventory.EAMError>).(closure #1).(closure #1) at ProjectDal.swift) -> ()) -> ()).(closure #1) + 110 at BaseDal.swift:33 frame #18: 0x00000001036df4b7 EAMInventorythunk + 39 at PhotosEditViewController.swift:0
    frame Support complex query #19: 0x0000000109e22d9d libdispatch.dylib_dispatch_call_block_and_release + 12 frame #20: 0x0000000109e433eb libdispatch.dylib_dispatch_client_callout + 8
    frame How to set NULL for a column of 'double' type? #21: 0x0000000109e2982c libdispatch.dylib_dispatch_queue_drain + 2215 frame #22: 0x0000000109e28d4d libdispatch.dylib_dispatch_queue_invoke + 601
    frame is there any way to support like statement? #23: 0x0000000109e2b996 libdispatch.dylib_dispatch_root_queue_drain + 1420 frame #24: 0x0000000109e2b405 libdispatch.dylib_dispatch_worker_thread3 + 111
    frame NSDate property can not be saved in transaction #25: 0x000000010a1974de libsystem_pthread.dylib_pthread_wqthread + 1129 frame #26: 0x000000010a195341 libsystem_pthread.dylibstart_wqthread + 13

    thread Subclassing support #8: tid = 0x38230a, 0x000000010a1ccf72 libsystem_kernel.dylibmach_msg_trap + 10, name = 'com.apple.NSURLConnectionLoader' frame #0: 0x000000010a1ccf72 libsystem_kernel.dylibmach_msg_trap + 10
    frame Fixed for multiple joins & joins based on A->B->C. Fixed compiler warnings. #1: 0x000000010a1cc3b3 libsystem_kernel.dylibmach_msg + 55 frame #2: 0x000000010562d434 CoreFoundationCFRunLoopServiceMachPort + 212
    frame Added new print output format #3: 0x000000010562c88f CoreFoundation__CFRunLoopRun + 1295 frame #4: 0x000000010562c0f8 CoreFoundationCFRunLoopRunSpecific + 488
    frame Incremented version in Header to 2.0.3 & Podspec #5: 0x000000010978ad24 CFNetwork+[NSURLConnection(Loader) _resourceLoadLoop:] + 412 frame #6: 0x0000000104acf12b Foundation__NSThread__start
    + 1198
    frame Inheritance Support? #7: 0x000000010a19799d libsystem_pthread.dylib_pthread_body + 131 frame #8: 0x000000010a19791a libsystem_pthread.dylib_pthread_start + 168
    frame support for Carthage #9: 0x000000010a195351 libsystem_pthread.dylib`thread_start + 13

    thread support for Carthage #9: tid = 0x382326, 0x000000010a1d307a libsystem_kernel.dylib__select + 10, name = 'com.apple.CFSocket.private' frame #0: 0x000000010a1d307a libsystem_kernel.dylib__select + 10
    frame Fixed for multiple joins & joins based on A->B->C. Fixed compiler warnings. #1: 0x00000001056725ea CoreFoundation__CFSocketManager + 746 frame #2: 0x000000010a19799d libsystem_pthread.dylib_pthread_body + 131
    frame Added new print output format #3: 0x000000010a19791a libsystem_pthread.dylib_pthread_start + 168 frame #4: 0x000000010a195351 libsystem_pthread.dylibthread_start + 13

@lbwxly
Copy link

lbwxly commented Oct 19, 2016

happen again

@editfmah
Copy link
Owner

Thanks, I think I may have found the bug from the information you provided. I will check it out now and post a fix. By rights it should just crash, but it doesn't. It just hangs instead.

@lbwxly
Copy link

lbwxly commented Oct 19, 2016

so, it seem two thread access systemEntityRelationships at the same time?

@editfmah
Copy link
Owner

yep, when a static is accessed it seems to block the main thread. I'm just removing the statics and putting them into a class. Those items are a bit of a throwback to some original code when the framework was just c & c++

@editfmah
Copy link
Owner

Okay, to do this right is going to take some time. ETA on a fix is tomorrow by the looks of it, subject to passing all the tests.

@Parkyprg
Copy link
Author

Thank you Adrian. I will try this fix too.
Can you release it on pods too?

@editfmah
Copy link
Owner

Just done it v2.0.9 should be showing, thanks @Parkyprg for being so patient. It was only when the second report came in that I could even see the pattern.

It may not fix it (considering I really struggled to replicate it), but i'd be really surprised if it didn't :)

@Parkyprg
Copy link
Author

:)
Thank you.

@editfmah
Copy link
Owner

editfmah commented Oct 22, 2016

Is this looking good now? It has caused a performance drop in the ORM, but that will be dealt with separately.

@lbwxly
Copy link

lbwxly commented Oct 23, 2016

i just get the latest code. look good for now. if any issue found, we will let you know. by the way, i have made some changes on my local branch(some changes about printing sql log base on setting, KVO related bug fix and some additional convenient methods), can i send a pull request?

@editfmah
Copy link
Owner

Yes please do.

@lbwxly
Copy link

lbwxly commented Oct 24, 2016

i think your change may not fix the problem, the problem is two thread access/modify the systemEntityRelationships list, but your change is wrap the getting logic of the member and add lock in the getting method. it won't avoid the access/modification to the list from two threads after they get the list object with a thread safe wrapper.

@lbwxly
Copy link

lbwxly commented Oct 24, 2016

The problem is still existing. i run bt all when it occur, get the same result as before, not sure if the problem is access [Class description] in different thread.

@lbwxly
Copy link

lbwxly commented Oct 24, 2016

i guess the problem is on code [r.sourceClass description]

@editfmah
Copy link
Owner

editfmah commented Oct 24, 2016

Those calls to get the systemEntityRelationships create a copy of that dictionary, so that should make it thread-safe (from an iteration point of view), now there might be two things accessing the objects within the dictionary which will be the same, but, as they are being used RO there should never have been a problem accessing them as a single static either. I only wrapped a lock around them to ensure there were not two copies being made at the same time. I strongly believe this to be a problem with apple's implementation of their block dispatcher, which seems to lock threads when creating/copying stack objects.

I had other plans for how I was going to deal with all these statics, event registry, backing store & re-implement the caching that would largely do away with large swathes of this code, but I was unsure as to weather it will actually be faster (more performant) in the long run. It would enable good memory savings and some CPU gains on some operations, but retrieving a properties value may well become slower, which would be a more consistent performance concern.

As for description, that is simple string manipulation and work on the heap. And there is a heap per thread anyway, so this should never clash.

@editfmah
Copy link
Owner

Anyhow, I will look again at this. Because those changes made the ORM much slower, so if it is not the static objects, then they should go back or be re-implemented differently as this is one scenario where OO is the worst possible solution for this.

@lbwxly
Copy link

lbwxly commented Oct 24, 2016

I have a suggestion on removing the lock and make the call faster: setup all SRKObject class( i mean setupClass method in SRKObject class) and setup all the required list objects(tableSchema,relationships...) when the open method is called. In this way, the database and the schema information in memory will be setup when open method is called, then the list won't be modified in the app's life cycle. there is only read operation, the lock can be removed. anything is incorrect?

@editfmah
Copy link
Owner

So you could test that by using the setupClasses method, which does nothing but ensure that all the classes are "touched" well in advance of being used in anger which achieves the same result. But none of the incidents indicate any objects being freshly initialised, which would leave them as read only.

@lbwxly
Copy link

lbwxly commented Oct 24, 2016

i will make the change and test.

@Parkyprg
Copy link
Author

Ok - so in my application I am able to reproduce this freeze anytime now.
The situation is like this:
On the main thread, I am populating a UITableView with some records from a table.
In a background thread, I am making a server request to bring some data and when it completes, I am storing this in a few tables.
If the server response comes in the same time when I populate the table, I got the freeze.

Issuing a 'bt all' command gives me the following:
`(lldb) bt all

In Thread #5, I can see WAITING_FOR_ANOTHER_THREAD_TO_FINISH_CALLING, while the main thread is in __ulock_wait status. So here is the deadlock.
If a comment in the background thread all aspects to database, the code is not freezing.

Is this related to network access somehow?
If I make a new project and fire a bunch of threads with database read/writes, everything goes smoothly.

@editfmah
Copy link
Owner

editfmah commented Oct 24, 2016

No, I think @lbwxly is on to something, it looks like the _class_initialize of these classes on different threads at the same time is causing the issue. It does some reading and writing to a few arrays and dictionaries, which we just split out to try and solve it. But what they point to is being potentially mutated.

Normally, any kind of access to the same object would just crash. But maybe, your example is suggesting that the _class_initialize is being called from two threads at the same time even though the +initialize method should only ever be called once for a class.

@lbwxly
Copy link

lbwxly commented Oct 24, 2016

@Parkyprg, you can try to call description method of all sub-classes of SRKObject class when your app launch. i think the freeze will disappear.
i mean the code like this: Person.description()

@lbwxly
Copy link

lbwxly commented Oct 24, 2016

@editfmah i suspect the [Class description] is not thread safe, in @Parkyprg 's thread log, all thread are blocked at objc_getProperty(i guess is called by [Class description]). i will do some test tomorrow.

@editfmah
Copy link
Owner

editfmah commented Oct 24, 2016

Thanks, @lbwxly & @Parkyprg. It's great that it can be quickly replicated. Just a couple of points though.

I can't see anything about the description overload that should cause any locking like this. As there should be a new IMP to that method for every call, and a new stack per thread.

Also, although the first hang looked like it might be on the call to description, the objc_getProperty call should have left the stack pointer inside the +description call. Plus, I don't think it will be treated as a property, i think that error is in the call:

to r.sourceClass.

Nestled away was this: Which is also significant (I think)

frame #3: 0x00000001904f13bc libobjc.A.dylibWAITING_FOR_ANOTHER_THREAD_TO_FINISH_CALLING_+initialize + 84

@Parkyprg
Copy link
Author

Thank you @lbwxly - after calling [Person description]; on all SRKObject classes right at the beginning of the app, it seems I am no longer getting any freezes in my app.
I will do more tests, but this hint definitely seems to help.

@lbwxly
Copy link

lbwxly commented Oct 24, 2016

@editfmah i want to send a pull request(submit the change i mentioned yesterday), but github desktop tell me i don't have permission on the project.

@editfmah
Copy link
Owner

@lbwxly I have added you to the project, you should have an invite to the team. Normally, you fork the codebase into your own repository and then we do pull requests from there. For some reason i'm limited to just 5 users on the main repository which is something i'm trying to work out right now.

@Parkyprg
Copy link
Author

Parkyprg commented Apr 3, 2017

This issue can be closed.
The fix is calling SRKObject's description in application:didFinishLaunchingWithOptions:

Thank you for your support.

@editfmah editfmah closed this as completed Apr 3, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants