Skip to content

Accessing currentUser on multiple threads causing deadlock #61

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

Closed
eeallen1 opened this issue Aug 19, 2015 · 23 comments
Closed

Accessing currentUser on multiple threads causing deadlock #61

eeallen1 opened this issue Aug 19, 2015 · 23 comments

Comments

@eeallen1
Copy link
Contributor

When I'm launching my app, there are several places where I'm using PFUser.CurrentUser - mostly for queries, but also a couple of writes. It looks like the deadlock occurs when one thread is setting an object on currentUser while another is using it in a query, but I'm not entirely sure.

Here is a stack trace:
screen shot 2015-08-19 at 4 13 08 pm

I know that there have been similar issues opened and resolved for other releases, and it may be that 1.8 has nothing to do with it, but it only started happening in the last couple of days (after I updated).

Some more details:

  • Deadlock doesn't occur every launch, and it appears to happen much more frequently on older devices (iphone 4s) than the newer models. It almost never occurs on the simulator.
  • I've tried commenting out dozens of lines of code that the stack trace points to, but it always end up getting hung somewhere else. I haven't procedurally uncommented and tested every call to currentUser because so much code depends on it, but that'll be my next step for troubleshooting.

Edit
Is it possible that the deadlock is occurring during Facebook authentication while I'm trying to query/modify currentUser elsewhere? Take a look at this:

screen shot 2015-08-19 at 4 30 21 pm

@nlutsenko
Copy link
Contributor

Hey @eeallen1, thanks for reporting this.
I've tried to reproduce the problem, but it doesn't repro for me, I am going to try investigating it further and there is a single piece that I think the bug must be hiding behind.
I'll update this issue once I have more information or attach a PR to this.

@eeallen1
Copy link
Contributor Author

@nlutsenko If there's anything specific I can look for that would help you, let me know. I tried creating an "empty" version of my app with the same number of Parse requests, but I can't seem to recreate the error when I take out the processor-intensive parts of the app.

I don't know much about how multithreading works, but I'm guessing this issue only arises when the processor can't switch quickly enough between threads. I could be totally off base, but the deadlock does occur significantly less frequently on the simulator and the newest iPhone than on the iPhone 4s and 5.

@kross50
Copy link

kross50 commented Aug 26, 2015

happens to me too on 1.8.0 and 1.8.1 (as has happened on some previous versions of iOS SDK)... so i'm staying on 1.7.5 where it doesn't happen... seems to happen right after Facebook login after which i immediately make 5 PFQuerys serially in rapid succession (after one completes the next is kicked off). It freezes on the 3rd or 4th PFQuery. PFUser properties are assessed multiple times in this workflow.

@ahashp
Copy link

ahashp commented Aug 26, 2015

I was using 1.7.5, and I tried updating to 1.8.1 And immediately, I notice my app locks up very very frequently, oftening locking up more than 10 seconds at at time. I, too, have lots of PFQuery(s) after app launch, all of them has equal criteria on currentUser, some of them write to properties on currentUser. Looking at this repo's issue this, this issue seems to describe what I am experiencing. (I'm running this on iPhone 6 Plus, iOS 8.4)

@arunv
Copy link

arunv commented Aug 26, 2015

+1. I'm seeing deadlock. On PFUser. I have PFSubclassing on user, if it makes a difference.

Update: agreeing with @eeallen1 , my specific error case also seems to be coming from [PFFacebookAuthenticationProvider restoreAuthenticationWithAuthData:]

I have an already-logged-in facebook user. I'm guessing something in that function is indirectly trying to get to PFUser.sessionToken or PFUser._state, both of which are waiting on (self.lock), acquired in ([PFUser synchronizeAuthDataWithAuthType:])

@richardjrossiii richardjrossiii added type:bug Impaired feature or lacking behavior that is likely assumed and removed needs investigation labels Aug 26, 2015
@richardjrossiii richardjrossiii added this to the 1.8.2 milestone Aug 26, 2015
@richardjrossiii
Copy link
Contributor

I have found the issue and am working on a fix.

@nlutsenko
Copy link
Contributor

Hey guys, just wanted to update on this issue with a workaround:
The problem only happens with ParseFacebookUtils that is built to work with an old (v3) version of Facebook SDK. If you migrate to using the latest Facebook SDK (aka v4) - the problem will be fixed.

We are working on the fix and it should be out with 1.8.2 of the SDK very soon.

@ahashp
Copy link

ahashp commented Aug 27, 2015

@nlutsenko I am using ParseFacebookUtilsV4.framework and I still see the deadlock issue with 1.8.1 I do not think it is limited to v3. You guys might want to investigate further to have a complete handle on this bug.

@richardjrossiii
Copy link
Contributor

@innopage can you please post a stack trace? It would make tracking this down much simpler.

@despinoza
Copy link

I'm also experiencing the deadlock and think I can shed some like on reproducibility: if I compile my app with 1.8.* and run on a device where [PFUser currentUser] has been persisted with 1.7.* then the app deadlocks 100% of the time (my app also executes a series of PFQuery in the background while checking currentUser in the main thread). However, if I run on a device as a fresh install, no deadlock occurs. I'm using the local data store, but have not tested whether this may or may not contribute to the issue. Hope this helps!

@richardjrossiii
Copy link
Contributor

@despinoza If it's that reproducible, can we please have a stack trace? AFAIK, there's no difference between a PFUser stored with 1.7.5 and one stored with 1.8.0.

@eeallen1
Copy link
Contributor Author

I wanted to add that I don't seem to get this behavior on Parse version 1.7.5, but when I tried to revert, I was getting compilation errors.

I'm using CocoaPods, and I was using version 0.38.0, but I was having the problem detailed in this thread: CocoaPods/Specs#13253

So as a temporary fix, I just reverted to Parse 1.7.5 and CocoaPods 0.37 - just in case anyone had trouble rolling back while using a newer version of CocoaPods. If a fix for this deadlock is released in 1.8.2, I assume it will be safe to update cocoapods as well.

@nlutsenko nlutsenko removed this from the 1.8.2 milestone Aug 28, 2015
@parse-github-bot
Copy link

Thank you for your feedback. We prioritize issues that have clear and concise repro steps. Please see our Bug Reporting Guidelines about what information should be added to this issue.

In addition, you might find the following resources helpful:

@nlutsenko nlutsenko added needs repro and removed type:bug Impaired feature or lacking behavior that is likely assumed labels Aug 28, 2015
@nlutsenko
Copy link
Contributor

Hey guys, just wanted to let everyone here now.
Parse SDK 1.8.2 is out and available right now, together with ParseFacebookUtils 1.8.2.
All available on the website - https://parse.com/docs/downloads as well as through Cocoapods.

This should help resolve some of the deadlocks that you guys are experiencing here.
I'll leave this issue open, and mark as needs repro/needs investigation, since we don't have a good repro case for any of the other deadlocks, other than ParseFacebookUtils one.

@ahashp
Copy link

ahashp commented Aug 28, 2015

I just tried 1.8.2, unfortunately, it has NOT solved my case, it's still locking up, CPU on iPhone at 99% most of the time, locking up the device. (I'm sticking to 1.7.5)

I'm not sure how to get a stack trace from a deadlock, (it's not an exception), pausing debugger in the middle of it doesn't show anything useful it seems.....any guide/hints?

@ahashp
Copy link

ahashp commented Aug 28, 2015

Okay, so I tried to pause the debugger whenever I see it's locking up. And most of the time, I see the Thread at this stacktrace attached.

A bit of background:

It is a Financial mobile app that calculates the value of a portfolio of transactions.

  • "Portfolio", "Transaction", "Stock" are all PFObject subclass
  • each "Transaction" has a column that is a pointer to "Portfolio", another pointer to "Stock"

Events:

  1. PFQuery the "Portfolio" from Parse
  2. PFQuery all the "Transactions" that has a pointer to this "Portfolio", in this case where I can reliably 100% lock it up, there are around 800 "Transactions", this PFQuery has "include" on "Stock" object
  3. Fetch prices of each "Stock" from my own servers (not Parse related)
  4. Loop through all 800 "Transactions", accessing its properties (of type string, number) frequently to do calculations.
  5. Repeat 3&4 every 10 seconds.

Prior in 1.7.5 , step 4 takes around 0.2 seconds to compute, now in 1.8.2, it takes around 5 seconds to compute, so effectively locking up my app half the time.

If I reduce the number of objects I receive in the PFQuery to less than 100 "Transactions", the lock up becomes less noticeable. So I think it is related quickly accessing lots of PFObjects ?

screen shot 2015-08-28 at 1 48 15 pm

@richardjrossiii
Copy link
Contributor

@innopage This seems like an unrelated issue, as that's not a true deadlock. I'm more than happy to investigate it, if you'd be willing to post it as a new issue. It may be related to the way we handle object subclassing, which changed somewhat before the 1.8.0 release.

Thanks for the report!

@ahashp
Copy link

ahashp commented Aug 28, 2015

Ok will create new issue

@eeallen1
Copy link
Contributor Author

The issue appears to be fixed for me with 1.8.2. Thanks @richardjrossiii and @nlutsenko !

richardjrossiii added a commit that referenced this issue Sep 23, 2015
By no longer holding a lock while recursing, we allow other threads who may be waiting on the current object to progress before iterating to children of the object, solving some of the deadlocks that we've seen in issues #11, #61, and #299.

This does not necessarily fix the above issues, as we probably still have similar deadlocks elsewhere in the codebase.

cc @grantland
richardjrossiii added a commit that referenced this issue Sep 23, 2015
By no longer holding a lock while recursing, we allow other threads who may be waiting on the current object to progress before iterating to children of the object, solving some of the deadlocks that we've seen in issues #11, #61, and #299.

This does not necessarily fix the above issues, as we probably still have similar deadlocks elsewhere in the codebase.

cc @grantland
@richardjrossiii
Copy link
Contributor

Hey guys, just pushed out a new branch today, richardross.collectdirtychildren.deadlock, that should fix at least one of the deadlocks that we've seen in this thread.

If you would like to test with that branch and see if it helps with your deadlocks, please feel free, and post stack traces if you still have deadlocks. Let's get these bugs squashed!

richardjrossiii added a commit that referenced this issue Sep 23, 2015
By no longer holding a lock while recursing, we allow other threads who may be waiting on the current object to progress before iterating to children of the object, solving some of the deadlocks that we've seen in issues #11, #61, and #299.

This does not necessarily fix the above issues, as we probably still have similar deadlocks elsewhere in the codebase.

cc @grantland
@despinoza
Copy link

@richardjrossiii I think our problem was due to an unexpected UI update on a background thread via continueWithBlock returned by [PFQuery findObjectsInBackground]. I'm assuming Parse 1.7 (though it may be the version of Bolts that shipped with it) called this block on the main thread and we lazily assumed that we could update the UI here. Moving our update to the main thread solved the problem for us and now Parse 1.8.X works fine 👍

@nlutsenko
Copy link
Contributor

Sounds about right, though I am not sure why we ever called continueWIthBlock there on the main thread. It's great that you found it, though!

continueWithBlock: has no guarantee about the thread it will call the block on (the implementation right now is to call the block immediately 19/20 times, with once offloading to a background thread via global dispatch queue to make sure we don't get the stack too deep).

Since it looks like the issue is fixed for everyone on this issue - I am going to close the issue.

@fsproru
Copy link

fsproru commented Nov 28, 2015

We had the same problem with Parse 1.8.1 and only upgrading to 1.10.0 fixed it. Thanks for fixing this issue in a later version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants